{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 前馈神经网络的流程\n",
    "1. 确定神经网络的层数和每层的神经元数\n",
    "2. 初始化参数W和b\n",
    "3. 进行循环迭代    \n",
    "（前向传播，得到预测值    \n",
    "计算损失函数   \n",
    "反向传播，得到参数W和b的梯度    \n",
    "对参数W和b进行更新）\n",
    "4. 对新数据做预测\n",
    "### 在前馈神经网络中，神经元的动作：\n",
    "【接受上一层数据作为输入>>线性变换>>激活变换>>输出数据到下一层】，每个神经元中有三个组成部分：权重(weight)矩阵W，偏置(bias)向量b，以及激活函数(activation function) g\n",
    "## 需解决的问题：\n",
    "1. 编程实现一个前馈神经网络，并使用前馈神经网络对实验六数据集进行分类。\n",
    "2. 探究不同激活函数对分类结果的影响。\n",
    "3. 设置合适的隐含层数量，避免梯度爆炸"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.preprocessing import LabelEncoder\n",
    "from sklearn.model_selection import train_test_split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "label_encoder = LabelEncoder()\n",
    "original_data = pd.read_csv(\"D:\\Lenovo\\Desktop\\云南大学\\空间数据挖掘\\实验数据\\data6.csv\")\n",
    "original_data['Forest']=label_encoder.fit_transform(original_data['Forest'])\n",
    "X_train,X_test,Y_train,Y_test = train_test_split(original_data.drop(['Forest','ID'],axis=1),original_data['Forest'],test_size=0.2,random_state=0)\n",
    "n0, m = X.shape\n",
    "n1 = 20\n",
    "n2 = 7\n",
    "n3 = 5\n",
    "n4 = 1\n",
    "layers_dims = [n0, n1, n2, n3, n4] # [12288, 20, 7, 5, 1] \n",
    "L = len(layers_dims) - 1  # 4层神经网络，不计输入层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#激活函数,sigmoid\n",
    "def sigmoid(x):\n",
    "    return 1 / (1 + np.exp(-x))\n",
    "\n",
    "\n",
    "#前向传播\n",
    "def forward_propagation(X,params,activations,prev_activations):\n",
    "    dz=params['dz']\n",
    "    dw=params['dw']\n",
    "    db=params['db']\n",
    "    dA=params['dA']\n",
    "    for l in range(1,L+1):\n",
    "        prev_activations[l]=np.dot(W[l],activations[l-1]+B[l])\n",
    "\n",
    "        activations[l]=sigmoid(prev_activations[l])\n",
    "\n",
    "        cross_entropy_cost=-1/m*np.dot(np.log(activations[L]),Y.T)\\\n",
    "            +np.dot(np.log(1-activations[L]),1-Y.T)\n",
    "        regularization_cost=0\n",
    "        for l in range(1,L+1):\n",
    "            regularization_cost+=np.sum(np.square(W[l]))*lambd/(2*m)\n",
    "            cost=cross_entropy_cost+regularization_cost\n",
    "\n",
    "#反向传播\n",
    "def backward_propagation(X,Y,params,activations,prev_activations):\n",
    "    dz=params['dz']\n",
    "    dw=params['dw']\n",
    "    db=params['db']\n",
    "    dA=params['dA']\n",
    "    W=params['W']\n",
    "    B=params['B']\n",
    "    L=params['L']\n",
    "    for l in reversed(range(1,L+1)):\n",
    "        if l==L:\n",
    "            dz[l]=dA[l]*activations[l]*(1-activations[l])\n",
    "        else:\n",
    "            dz[l]=dA[l].copy()\n",
    "            dz[l][prev_activations[l]<=0]=0\n",
    "        dw[l]=1/m*np.dot(dz[l],activations[l-1].T)+param_w[l]*lambd/m\n",
    "        db[l]=1/m*np.sum(dz[l],axis=1,keepdims=True)\n",
    "        dA[l-1]=np.dot(param_w[l].T,dz[l])\n",
    "\n",
    "        assert dz[l].shape==activations[l].shape\n",
    "        assert dw[l].shape==param_w[l].shape\n",
    "        assert db[l].shape==param_b[l].shape\n",
    "        assert dA[l-1].shape==activations[l-1].shape\n",
    "\n",
    "        param_w[l]=param_w[l]-learning_rate*dw[l]\n",
    "        param_b[l]=param_b[l]-learning_rate*db[l]\n",
    "\n",
    "    if i%100==0:\n",
    "        print(\"Cost after iteration {}: {}\".format(i,cost))\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "def neural_network(X,Y,learning_rate=0.01,num_iterations=2000,lambd=0):\n",
    "    m=X.shape[1]\n",
    "\n",
    "    param_w=[i for i in range(0,L+1)]\n",
    "    param_b=[i for i in range(0,L+1)]\n",
    "    np.random.seed(10)\n",
    "    for l in range(1,L+1):\n",
    "        if l<L:\n",
    "            param_w[l]=np.random.randn(layers_dims[l],layers_dims[l-1])*np.sqrt(2/layers_dims[l-1])\n",
    "        if l==L:\n",
    "            param_w[l]=np.random.randn(layers_dims[l],layers_dims[l-1])*0.01\n",
    "        param_b[l]=np.zeros((layers_dims[l],1))\n",
    "    \n",
    "    activations=[X,]+[i for i in range(0,L)]\n",
    "    prev_activations=[i for i in range(0,L+1)]\n",
    "    dA=[i for i in range(0,L+1)]\n",
    "    dz=[i for i in range(0,L+1)]\n",
    "    dw=[i for i in range(0,L+1)]\n",
    "    db=[i for i in range(0,L+1)]\n",
    "\n",
    "    params={'dz':dz,'dw':dw,'db':db,'dA':dA,'W':param_w,'B':param_b,'L':L}\n",
    "    for i in range(num_iterations):\n",
    "        forward_propagation(X,Y,params,activations,prev_activations)\n",
    "\n",
    "\n",
    "    dA[L]=np.divide(1-Y,1-activations[L])-np.divide(Y,activations[L])\n",
    "    assert dA[L].shape==(1,m)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 正式实验部分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({0: 1110, 1: 298}) Counter({0: 278, 1: 75})\n"
     ]
    }
   ],
   "source": [
    "import csv\n",
    "import pandas as pd\n",
    "import random\n",
    "import math\n",
    "from sklearn.model_selection import train_test_split\n",
    "from collections import Counter\n",
    "from imblearn.over_sampling import RandomOverSampler\n",
    "from imblearn.under_sampling import RandomUnderSampler\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "def read_csv(filename,test_size=0.2):\n",
    "    \"\"\"读取csv文件，并返回数据和标签。\"\"\"\n",
    "    # data = []\n",
    "    # labels = []\n",
    "    # with open(filename, 'r') as file:\n",
    "        \n",
    "    #     reader = csv.reader(file)\n",
    "    #     next(reader)  # 跳过头行\n",
    "    #     for row in reader:\n",
    "    #         features = list(map(float, row[1:-1]))\n",
    "    #         label = int(row['Forest'])\n",
    "    #         data.append(features)\n",
    "    #         labels.append(label)\n",
    "    # return data, labels\n",
    "\n",
    "    dataset=pd.read_csv(filename)\n",
    "    data=dataset.iloc[:,1:-1].values\n",
    "    labels=dataset['Forest'].values\n",
    "    X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=0,\n",
    "                                                        stratify=dataset['Forest'])\n",
    "    return X_train, y_train,X_test, y_test,dataset\n",
    "ss=StandardScaler()\n",
    "X_train, y_train,X_test, y_test,dataset = read_csv(\"D:\\Lenovo\\Desktop\\云南大学\\空间数据挖掘\\实验数据\\data6.csv\")\n",
    "print(Counter(y_train),Counter(y_test))\n",
    "\n",
    "X_train=ss.fit_transform(X_train)\n",
    "X_test=ss.transform(X_test)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/200 - Train Loss: 0.4713, Train Accuracy: 0.7884, Validation Loss: 0.4615, Validation Accuracy: 0.7875\n",
      "Epoch 2/200 - Train Loss: 0.3511, Train Accuracy: 0.7884, Validation Loss: 0.3414, Validation Accuracy: 0.7875\n",
      "Epoch 3/200 - Train Loss: 0.1803, Train Accuracy: 0.7379, Validation Loss: 0.1734, Validation Accuracy: 0.7960\n",
      "Epoch 4/200 - Train Loss: 0.1620, Train Accuracy: 0.7003, Validation Loss: 0.1559, Validation Accuracy: 0.7535\n",
      "Epoch 5/200 - Train Loss: 0.1557, Train Accuracy: 0.6868, Validation Loss: 0.1500, Validation Accuracy: 0.7394\n",
      "Epoch 6/200 - Train Loss: 0.1507, Train Accuracy: 0.6875, Validation Loss: 0.1454, Validation Accuracy: 0.7365\n",
      "Epoch 7/200 - Train Loss: 0.1461, Train Accuracy: 0.6903, Validation Loss: 0.1412, Validation Accuracy: 0.7337\n",
      "Epoch 8/200 - Train Loss: 0.1419, Train Accuracy: 0.6939, Validation Loss: 0.1374, Validation Accuracy: 0.7394\n",
      "Epoch 9/200 - Train Loss: 0.1380, Train Accuracy: 0.6982, Validation Loss: 0.1338, Validation Accuracy: 0.7564\n",
      "Epoch 10/200 - Train Loss: 0.1344, Train Accuracy: 0.7010, Validation Loss: 0.1305, Validation Accuracy: 0.7620\n",
      "Epoch 11/200 - Train Loss: 0.1311, Train Accuracy: 0.7088, Validation Loss: 0.1275, Validation Accuracy: 0.7620\n",
      "Epoch 12/200 - Train Loss: 0.1281, Train Accuracy: 0.7138, Validation Loss: 0.1247, Validation Accuracy: 0.7677\n",
      "Epoch 13/200 - Train Loss: 0.1253, Train Accuracy: 0.7188, Validation Loss: 0.1221, Validation Accuracy: 0.7705\n",
      "Epoch 14/200 - Train Loss: 0.1228, Train Accuracy: 0.7237, Validation Loss: 0.1198, Validation Accuracy: 0.7734\n",
      "Epoch 15/200 - Train Loss: 0.1205, Train Accuracy: 0.7287, Validation Loss: 0.1176, Validation Accuracy: 0.7734\n",
      "Epoch 16/200 - Train Loss: 0.1184, Train Accuracy: 0.7330, Validation Loss: 0.1156, Validation Accuracy: 0.7734\n",
      "Epoch 17/200 - Train Loss: 0.1165, Train Accuracy: 0.7351, Validation Loss: 0.1137, Validation Accuracy: 0.7790\n",
      "Epoch 18/200 - Train Loss: 0.1147, Train Accuracy: 0.7372, Validation Loss: 0.1120, Validation Accuracy: 0.7847\n",
      "Epoch 19/200 - Train Loss: 0.1131, Train Accuracy: 0.7429, Validation Loss: 0.1105, Validation Accuracy: 0.7932\n",
      "Epoch 20/200 - Train Loss: 0.1116, Train Accuracy: 0.7436, Validation Loss: 0.1090, Validation Accuracy: 0.8017\n",
      "Epoch 21/200 - Train Loss: 0.1103, Train Accuracy: 0.7479, Validation Loss: 0.1077, Validation Accuracy: 0.8045\n",
      "Epoch 22/200 - Train Loss: 0.1090, Train Accuracy: 0.7514, Validation Loss: 0.1064, Validation Accuracy: 0.8017\n",
      "Epoch 23/200 - Train Loss: 0.1079, Train Accuracy: 0.7557, Validation Loss: 0.1053, Validation Accuracy: 0.8045\n",
      "Epoch 24/200 - Train Loss: 0.1068, Train Accuracy: 0.7578, Validation Loss: 0.1042, Validation Accuracy: 0.8045\n",
      "Epoch 25/200 - Train Loss: 0.1058, Train Accuracy: 0.7635, Validation Loss: 0.1032, Validation Accuracy: 0.8102\n",
      "Epoch 26/200 - Train Loss: 0.1049, Train Accuracy: 0.7649, Validation Loss: 0.1022, Validation Accuracy: 0.8130\n",
      "Epoch 27/200 - Train Loss: 0.1040, Train Accuracy: 0.7706, Validation Loss: 0.1013, Validation Accuracy: 0.8159\n",
      "Epoch 28/200 - Train Loss: 0.1032, Train Accuracy: 0.7720, Validation Loss: 0.1005, Validation Accuracy: 0.8187\n",
      "Epoch 29/200 - Train Loss: 0.1025, Train Accuracy: 0.7749, Validation Loss: 0.0997, Validation Accuracy: 0.8187\n",
      "Epoch 30/200 - Train Loss: 0.1018, Train Accuracy: 0.7805, Validation Loss: 0.0989, Validation Accuracy: 0.8187\n",
      "Epoch 31/200 - Train Loss: 0.1011, Train Accuracy: 0.7820, Validation Loss: 0.0982, Validation Accuracy: 0.8187\n",
      "Epoch 32/200 - Train Loss: 0.1005, Train Accuracy: 0.7855, Validation Loss: 0.0975, Validation Accuracy: 0.8215\n",
      "Epoch 33/200 - Train Loss: 0.0999, Train Accuracy: 0.7855, Validation Loss: 0.0968, Validation Accuracy: 0.8215\n",
      "Epoch 34/200 - Train Loss: 0.0993, Train Accuracy: 0.7876, Validation Loss: 0.0962, Validation Accuracy: 0.8215\n",
      "Epoch 35/200 - Train Loss: 0.0988, Train Accuracy: 0.7891, Validation Loss: 0.0956, Validation Accuracy: 0.8244\n",
      "Epoch 36/200 - Train Loss: 0.0982, Train Accuracy: 0.7933, Validation Loss: 0.0950, Validation Accuracy: 0.8244\n",
      "Epoch 37/200 - Train Loss: 0.0977, Train Accuracy: 0.7955, Validation Loss: 0.0945, Validation Accuracy: 0.8244\n",
      "Epoch 38/200 - Train Loss: 0.0972, Train Accuracy: 0.7990, Validation Loss: 0.0939, Validation Accuracy: 0.8244\n",
      "Epoch 39/200 - Train Loss: 0.0968, Train Accuracy: 0.7997, Validation Loss: 0.0934, Validation Accuracy: 0.8244\n",
      "Epoch 40/200 - Train Loss: 0.0963, Train Accuracy: 0.8011, Validation Loss: 0.0929, Validation Accuracy: 0.8244\n",
      "Epoch 41/200 - Train Loss: 0.0959, Train Accuracy: 0.8011, Validation Loss: 0.0924, Validation Accuracy: 0.8244\n",
      "Epoch 42/200 - Train Loss: 0.0955, Train Accuracy: 0.8040, Validation Loss: 0.0919, Validation Accuracy: 0.8244\n",
      "Epoch 43/200 - Train Loss: 0.0951, Train Accuracy: 0.8068, Validation Loss: 0.0914, Validation Accuracy: 0.8244\n",
      "Epoch 44/200 - Train Loss: 0.0947, Train Accuracy: 0.8075, Validation Loss: 0.0910, Validation Accuracy: 0.8272\n",
      "Epoch 45/200 - Train Loss: 0.0943, Train Accuracy: 0.8097, Validation Loss: 0.0905, Validation Accuracy: 0.8329\n",
      "Epoch 46/200 - Train Loss: 0.0939, Train Accuracy: 0.8118, Validation Loss: 0.0901, Validation Accuracy: 0.8329\n",
      "Epoch 47/200 - Train Loss: 0.0936, Train Accuracy: 0.8153, Validation Loss: 0.0897, Validation Accuracy: 0.8329\n",
      "Epoch 48/200 - Train Loss: 0.0932, Train Accuracy: 0.8168, Validation Loss: 0.0893, Validation Accuracy: 0.8329\n",
      "Epoch 49/200 - Train Loss: 0.0929, Train Accuracy: 0.8210, Validation Loss: 0.0889, Validation Accuracy: 0.8329\n",
      "Epoch 50/200 - Train Loss: 0.0925, Train Accuracy: 0.8210, Validation Loss: 0.0885, Validation Accuracy: 0.8329\n",
      "Epoch 51/200 - Train Loss: 0.0922, Train Accuracy: 0.8210, Validation Loss: 0.0881, Validation Accuracy: 0.8329\n",
      "Epoch 52/200 - Train Loss: 0.0919, Train Accuracy: 0.8239, Validation Loss: 0.0877, Validation Accuracy: 0.8329\n",
      "Epoch 53/200 - Train Loss: 0.0916, Train Accuracy: 0.8253, Validation Loss: 0.0874, Validation Accuracy: 0.8329\n",
      "Epoch 54/200 - Train Loss: 0.0913, Train Accuracy: 0.8253, Validation Loss: 0.0870, Validation Accuracy: 0.8329\n",
      "Epoch 55/200 - Train Loss: 0.0910, Train Accuracy: 0.8260, Validation Loss: 0.0867, Validation Accuracy: 0.8329\n",
      "Epoch 56/200 - Train Loss: 0.0907, Train Accuracy: 0.8267, Validation Loss: 0.0863, Validation Accuracy: 0.8329\n",
      "Epoch 57/200 - Train Loss: 0.0904, Train Accuracy: 0.8267, Validation Loss: 0.0860, Validation Accuracy: 0.8357\n",
      "Epoch 58/200 - Train Loss: 0.0901, Train Accuracy: 0.8267, Validation Loss: 0.0856, Validation Accuracy: 0.8357\n",
      "Epoch 59/200 - Train Loss: 0.0899, Train Accuracy: 0.8274, Validation Loss: 0.0853, Validation Accuracy: 0.8385\n",
      "Epoch 60/200 - Train Loss: 0.0896, Train Accuracy: 0.8288, Validation Loss: 0.0850, Validation Accuracy: 0.8385\n",
      "Epoch 61/200 - Train Loss: 0.0893, Train Accuracy: 0.8310, Validation Loss: 0.0847, Validation Accuracy: 0.8385\n",
      "Epoch 62/200 - Train Loss: 0.0891, Train Accuracy: 0.8310, Validation Loss: 0.0844, Validation Accuracy: 0.8385\n",
      "Epoch 63/200 - Train Loss: 0.0888, Train Accuracy: 0.8324, Validation Loss: 0.0841, Validation Accuracy: 0.8414\n",
      "Epoch 64/200 - Train Loss: 0.0886, Train Accuracy: 0.8324, Validation Loss: 0.0838, Validation Accuracy: 0.8442\n",
      "Epoch 65/200 - Train Loss: 0.0884, Train Accuracy: 0.8331, Validation Loss: 0.0835, Validation Accuracy: 0.8442\n",
      "Epoch 66/200 - Train Loss: 0.0881, Train Accuracy: 0.8352, Validation Loss: 0.0832, Validation Accuracy: 0.8499\n",
      "Epoch 67/200 - Train Loss: 0.0879, Train Accuracy: 0.8381, Validation Loss: 0.0830, Validation Accuracy: 0.8499\n",
      "Epoch 68/200 - Train Loss: 0.0877, Train Accuracy: 0.8402, Validation Loss: 0.0827, Validation Accuracy: 0.8527\n",
      "Epoch 69/200 - Train Loss: 0.0875, Train Accuracy: 0.8409, Validation Loss: 0.0824, Validation Accuracy: 0.8527\n",
      "Epoch 70/200 - Train Loss: 0.0872, Train Accuracy: 0.8423, Validation Loss: 0.0822, Validation Accuracy: 0.8527\n",
      "Epoch 71/200 - Train Loss: 0.0870, Train Accuracy: 0.8445, Validation Loss: 0.0819, Validation Accuracy: 0.8527\n",
      "Epoch 72/200 - Train Loss: 0.0868, Train Accuracy: 0.8466, Validation Loss: 0.0817, Validation Accuracy: 0.8555\n",
      "Epoch 73/200 - Train Loss: 0.0866, Train Accuracy: 0.8466, Validation Loss: 0.0814, Validation Accuracy: 0.8527\n",
      "Epoch 74/200 - Train Loss: 0.0864, Train Accuracy: 0.8487, Validation Loss: 0.0812, Validation Accuracy: 0.8527\n",
      "Epoch 75/200 - Train Loss: 0.0863, Train Accuracy: 0.8487, Validation Loss: 0.0810, Validation Accuracy: 0.8527\n",
      "Epoch 76/200 - Train Loss: 0.0861, Train Accuracy: 0.8501, Validation Loss: 0.0807, Validation Accuracy: 0.8527\n",
      "Epoch 77/200 - Train Loss: 0.0859, Train Accuracy: 0.8509, Validation Loss: 0.0805, Validation Accuracy: 0.8527\n",
      "Epoch 78/200 - Train Loss: 0.0857, Train Accuracy: 0.8516, Validation Loss: 0.0803, Validation Accuracy: 0.8555\n",
      "Epoch 79/200 - Train Loss: 0.0855, Train Accuracy: 0.8530, Validation Loss: 0.0801, Validation Accuracy: 0.8555\n",
      "Epoch 80/200 - Train Loss: 0.0854, Train Accuracy: 0.8530, Validation Loss: 0.0799, Validation Accuracy: 0.8555\n",
      "Epoch 81/200 - Train Loss: 0.0852, Train Accuracy: 0.8544, Validation Loss: 0.0797, Validation Accuracy: 0.8555\n",
      "Epoch 82/200 - Train Loss: 0.0850, Train Accuracy: 0.8558, Validation Loss: 0.0795, Validation Accuracy: 0.8555\n",
      "Epoch 83/200 - Train Loss: 0.0849, Train Accuracy: 0.8558, Validation Loss: 0.0793, Validation Accuracy: 0.8555\n",
      "Epoch 84/200 - Train Loss: 0.0847, Train Accuracy: 0.8587, Validation Loss: 0.0791, Validation Accuracy: 0.8555\n",
      "Epoch 85/200 - Train Loss: 0.0846, Train Accuracy: 0.8587, Validation Loss: 0.0789, Validation Accuracy: 0.8555\n",
      "Epoch 86/200 - Train Loss: 0.0844, Train Accuracy: 0.8601, Validation Loss: 0.0787, Validation Accuracy: 0.8555\n",
      "Epoch 87/200 - Train Loss: 0.0843, Train Accuracy: 0.8629, Validation Loss: 0.0785, Validation Accuracy: 0.8555\n",
      "Epoch 88/200 - Train Loss: 0.0841, Train Accuracy: 0.8636, Validation Loss: 0.0783, Validation Accuracy: 0.8584\n",
      "Epoch 89/200 - Train Loss: 0.0840, Train Accuracy: 0.8636, Validation Loss: 0.0781, Validation Accuracy: 0.8584\n",
      "Epoch 90/200 - Train Loss: 0.0839, Train Accuracy: 0.8629, Validation Loss: 0.0780, Validation Accuracy: 0.8555\n",
      "Epoch 91/200 - Train Loss: 0.0837, Train Accuracy: 0.8629, Validation Loss: 0.0778, Validation Accuracy: 0.8555\n",
      "Epoch 92/200 - Train Loss: 0.0836, Train Accuracy: 0.8636, Validation Loss: 0.0776, Validation Accuracy: 0.8612\n",
      "Epoch 93/200 - Train Loss: 0.0835, Train Accuracy: 0.8643, Validation Loss: 0.0775, Validation Accuracy: 0.8640\n",
      "Epoch 94/200 - Train Loss: 0.0834, Train Accuracy: 0.8643, Validation Loss: 0.0773, Validation Accuracy: 0.8640\n",
      "Epoch 95/200 - Train Loss: 0.0832, Train Accuracy: 0.8643, Validation Loss: 0.0772, Validation Accuracy: 0.8669\n",
      "Epoch 96/200 - Train Loss: 0.0831, Train Accuracy: 0.8665, Validation Loss: 0.0770, Validation Accuracy: 0.8697\n",
      "Epoch 97/200 - Train Loss: 0.0830, Train Accuracy: 0.8665, Validation Loss: 0.0769, Validation Accuracy: 0.8697\n",
      "Epoch 98/200 - Train Loss: 0.0829, Train Accuracy: 0.8665, Validation Loss: 0.0767, Validation Accuracy: 0.8697\n",
      "Epoch 99/200 - Train Loss: 0.0828, Train Accuracy: 0.8665, Validation Loss: 0.0766, Validation Accuracy: 0.8697\n",
      "Epoch 100/200 - Train Loss: 0.0827, Train Accuracy: 0.8679, Validation Loss: 0.0764, Validation Accuracy: 0.8697\n",
      "Epoch 101/200 - Train Loss: 0.0826, Train Accuracy: 0.8672, Validation Loss: 0.0763, Validation Accuracy: 0.8697\n",
      "Epoch 102/200 - Train Loss: 0.0825, Train Accuracy: 0.8665, Validation Loss: 0.0762, Validation Accuracy: 0.8697\n",
      "Epoch 103/200 - Train Loss: 0.0824, Train Accuracy: 0.8658, Validation Loss: 0.0760, Validation Accuracy: 0.8697\n",
      "Epoch 104/200 - Train Loss: 0.0823, Train Accuracy: 0.8658, Validation Loss: 0.0759, Validation Accuracy: 0.8697\n",
      "Epoch 105/200 - Train Loss: 0.0822, Train Accuracy: 0.8658, Validation Loss: 0.0758, Validation Accuracy: 0.8697\n",
      "Epoch 106/200 - Train Loss: 0.0821, Train Accuracy: 0.8658, Validation Loss: 0.0757, Validation Accuracy: 0.8725\n",
      "Epoch 107/200 - Train Loss: 0.0820, Train Accuracy: 0.8665, Validation Loss: 0.0755, Validation Accuracy: 0.8725\n",
      "Epoch 108/200 - Train Loss: 0.0819, Train Accuracy: 0.8679, Validation Loss: 0.0754, Validation Accuracy: 0.8725\n",
      "Epoch 109/200 - Train Loss: 0.0818, Train Accuracy: 0.8672, Validation Loss: 0.0753, Validation Accuracy: 0.8782\n",
      "Epoch 110/200 - Train Loss: 0.0818, Train Accuracy: 0.8672, Validation Loss: 0.0752, Validation Accuracy: 0.8782\n",
      "Epoch 111/200 - Train Loss: 0.0817, Train Accuracy: 0.8651, Validation Loss: 0.0751, Validation Accuracy: 0.8782\n",
      "Epoch 112/200 - Train Loss: 0.0816, Train Accuracy: 0.8658, Validation Loss: 0.0750, Validation Accuracy: 0.8782\n",
      "Epoch 113/200 - Train Loss: 0.0815, Train Accuracy: 0.8672, Validation Loss: 0.0749, Validation Accuracy: 0.8782\n",
      "Epoch 114/200 - Train Loss: 0.0814, Train Accuracy: 0.8672, Validation Loss: 0.0748, Validation Accuracy: 0.8782\n",
      "Epoch 115/200 - Train Loss: 0.0814, Train Accuracy: 0.8679, Validation Loss: 0.0746, Validation Accuracy: 0.8810\n",
      "Epoch 116/200 - Train Loss: 0.0813, Train Accuracy: 0.8686, Validation Loss: 0.0745, Validation Accuracy: 0.8810\n",
      "Epoch 117/200 - Train Loss: 0.0812, Train Accuracy: 0.8700, Validation Loss: 0.0744, Validation Accuracy: 0.8839\n",
      "Epoch 118/200 - Train Loss: 0.0812, Train Accuracy: 0.8700, Validation Loss: 0.0743, Validation Accuracy: 0.8867\n",
      "Epoch 119/200 - Train Loss: 0.0811, Train Accuracy: 0.8714, Validation Loss: 0.0743, Validation Accuracy: 0.8867\n",
      "Epoch 120/200 - Train Loss: 0.0810, Train Accuracy: 0.8707, Validation Loss: 0.0742, Validation Accuracy: 0.8839\n",
      "Epoch 121/200 - Train Loss: 0.0810, Train Accuracy: 0.8707, Validation Loss: 0.0741, Validation Accuracy: 0.8839\n",
      "Epoch 122/200 - Train Loss: 0.0809, Train Accuracy: 0.8707, Validation Loss: 0.0740, Validation Accuracy: 0.8867\n",
      "Epoch 123/200 - Train Loss: 0.0808, Train Accuracy: 0.8707, Validation Loss: 0.0739, Validation Accuracy: 0.8895\n",
      "Epoch 124/200 - Train Loss: 0.0808, Train Accuracy: 0.8707, Validation Loss: 0.0738, Validation Accuracy: 0.8895\n",
      "Epoch 125/200 - Train Loss: 0.0807, Train Accuracy: 0.8707, Validation Loss: 0.0737, Validation Accuracy: 0.8924\n",
      "Epoch 126/200 - Train Loss: 0.0807, Train Accuracy: 0.8714, Validation Loss: 0.0736, Validation Accuracy: 0.8952\n",
      "Epoch 127/200 - Train Loss: 0.0806, Train Accuracy: 0.8714, Validation Loss: 0.0735, Validation Accuracy: 0.8952\n",
      "Epoch 128/200 - Train Loss: 0.0805, Train Accuracy: 0.8700, Validation Loss: 0.0735, Validation Accuracy: 0.8924\n",
      "Epoch 129/200 - Train Loss: 0.0805, Train Accuracy: 0.8700, Validation Loss: 0.0734, Validation Accuracy: 0.8924\n",
      "Epoch 130/200 - Train Loss: 0.0804, Train Accuracy: 0.8714, Validation Loss: 0.0733, Validation Accuracy: 0.8924\n",
      "Epoch 131/200 - Train Loss: 0.0804, Train Accuracy: 0.8707, Validation Loss: 0.0732, Validation Accuracy: 0.8924\n",
      "Epoch 132/200 - Train Loss: 0.0803, Train Accuracy: 0.8707, Validation Loss: 0.0731, Validation Accuracy: 0.8952\n",
      "Epoch 133/200 - Train Loss: 0.0803, Train Accuracy: 0.8700, Validation Loss: 0.0731, Validation Accuracy: 0.8952\n",
      "Epoch 134/200 - Train Loss: 0.0802, Train Accuracy: 0.8714, Validation Loss: 0.0730, Validation Accuracy: 0.8952\n",
      "Epoch 135/200 - Train Loss: 0.0802, Train Accuracy: 0.8714, Validation Loss: 0.0729, Validation Accuracy: 0.8952\n",
      "Epoch 136/200 - Train Loss: 0.0801, Train Accuracy: 0.8707, Validation Loss: 0.0729, Validation Accuracy: 0.8980\n",
      "Epoch 137/200 - Train Loss: 0.0801, Train Accuracy: 0.8714, Validation Loss: 0.0728, Validation Accuracy: 0.8980\n",
      "Epoch 138/200 - Train Loss: 0.0800, Train Accuracy: 0.8714, Validation Loss: 0.0727, Validation Accuracy: 0.8980\n",
      "Epoch 139/200 - Train Loss: 0.0800, Train Accuracy: 0.8714, Validation Loss: 0.0726, Validation Accuracy: 0.8980\n",
      "Epoch 140/200 - Train Loss: 0.0800, Train Accuracy: 0.8714, Validation Loss: 0.0726, Validation Accuracy: 0.9008\n",
      "Epoch 141/200 - Train Loss: 0.0799, Train Accuracy: 0.8722, Validation Loss: 0.0725, Validation Accuracy: 0.9037\n",
      "Epoch 142/200 - Train Loss: 0.0799, Train Accuracy: 0.8714, Validation Loss: 0.0725, Validation Accuracy: 0.9037\n",
      "Epoch 143/200 - Train Loss: 0.0798, Train Accuracy: 0.8722, Validation Loss: 0.0724, Validation Accuracy: 0.9037\n",
      "Epoch 144/200 - Train Loss: 0.0798, Train Accuracy: 0.8722, Validation Loss: 0.0723, Validation Accuracy: 0.9037\n",
      "Epoch 145/200 - Train Loss: 0.0798, Train Accuracy: 0.8729, Validation Loss: 0.0723, Validation Accuracy: 0.9037\n",
      "Epoch 146/200 - Train Loss: 0.0797, Train Accuracy: 0.8729, Validation Loss: 0.0722, Validation Accuracy: 0.9037\n",
      "Epoch 147/200 - Train Loss: 0.0797, Train Accuracy: 0.8743, Validation Loss: 0.0721, Validation Accuracy: 0.9037\n",
      "Epoch 148/200 - Train Loss: 0.0796, Train Accuracy: 0.8743, Validation Loss: 0.0721, Validation Accuracy: 0.9037\n",
      "Epoch 149/200 - Train Loss: 0.0796, Train Accuracy: 0.8743, Validation Loss: 0.0720, Validation Accuracy: 0.9037\n",
      "Epoch 150/200 - Train Loss: 0.0796, Train Accuracy: 0.8757, Validation Loss: 0.0720, Validation Accuracy: 0.9037\n",
      "Epoch 151/200 - Train Loss: 0.0795, Train Accuracy: 0.8757, Validation Loss: 0.0719, Validation Accuracy: 0.9037\n",
      "Epoch 152/200 - Train Loss: 0.0795, Train Accuracy: 0.8757, Validation Loss: 0.0719, Validation Accuracy: 0.9037\n",
      "Epoch 153/200 - Train Loss: 0.0795, Train Accuracy: 0.8757, Validation Loss: 0.0718, Validation Accuracy: 0.9037\n",
      "Epoch 154/200 - Train Loss: 0.0794, Train Accuracy: 0.8764, Validation Loss: 0.0718, Validation Accuracy: 0.9037\n",
      "Epoch 155/200 - Train Loss: 0.0794, Train Accuracy: 0.8764, Validation Loss: 0.0717, Validation Accuracy: 0.9037\n",
      "Epoch 156/200 - Train Loss: 0.0794, Train Accuracy: 0.8764, Validation Loss: 0.0717, Validation Accuracy: 0.9065\n",
      "Epoch 157/200 - Train Loss: 0.0794, Train Accuracy: 0.8736, Validation Loss: 0.0716, Validation Accuracy: 0.9065\n",
      "Epoch 158/200 - Train Loss: 0.0793, Train Accuracy: 0.8743, Validation Loss: 0.0716, Validation Accuracy: 0.9065\n",
      "Epoch 159/200 - Train Loss: 0.0793, Train Accuracy: 0.8743, Validation Loss: 0.0715, Validation Accuracy: 0.9065\n",
      "Epoch 160/200 - Train Loss: 0.0793, Train Accuracy: 0.8750, Validation Loss: 0.0715, Validation Accuracy: 0.9065\n",
      "Epoch 161/200 - Train Loss: 0.0792, Train Accuracy: 0.8743, Validation Loss: 0.0714, Validation Accuracy: 0.9065\n",
      "Epoch 162/200 - Train Loss: 0.0792, Train Accuracy: 0.8750, Validation Loss: 0.0714, Validation Accuracy: 0.9065\n",
      "Epoch 163/200 - Train Loss: 0.0792, Train Accuracy: 0.8750, Validation Loss: 0.0713, Validation Accuracy: 0.9065\n",
      "Epoch 164/200 - Train Loss: 0.0792, Train Accuracy: 0.8750, Validation Loss: 0.0713, Validation Accuracy: 0.9065\n",
      "Epoch 165/200 - Train Loss: 0.0791, Train Accuracy: 0.8750, Validation Loss: 0.0712, Validation Accuracy: 0.9065\n",
      "Epoch 166/200 - Train Loss: 0.0791, Train Accuracy: 0.8750, Validation Loss: 0.0712, Validation Accuracy: 0.9065\n",
      "Epoch 167/200 - Train Loss: 0.0791, Train Accuracy: 0.8750, Validation Loss: 0.0712, Validation Accuracy: 0.9065\n",
      "Epoch 168/200 - Train Loss: 0.0791, Train Accuracy: 0.8750, Validation Loss: 0.0711, Validation Accuracy: 0.9065\n",
      "Epoch 169/200 - Train Loss: 0.0790, Train Accuracy: 0.8764, Validation Loss: 0.0711, Validation Accuracy: 0.9065\n",
      "Epoch 170/200 - Train Loss: 0.0790, Train Accuracy: 0.8764, Validation Loss: 0.0710, Validation Accuracy: 0.9065\n",
      "Epoch 171/200 - Train Loss: 0.0790, Train Accuracy: 0.8764, Validation Loss: 0.0710, Validation Accuracy: 0.9065\n",
      "Epoch 172/200 - Train Loss: 0.0790, Train Accuracy: 0.8771, Validation Loss: 0.0709, Validation Accuracy: 0.9065\n",
      "Epoch 173/200 - Train Loss: 0.0789, Train Accuracy: 0.8771, Validation Loss: 0.0709, Validation Accuracy: 0.9065\n",
      "Epoch 174/200 - Train Loss: 0.0789, Train Accuracy: 0.8771, Validation Loss: 0.0709, Validation Accuracy: 0.9065\n",
      "Epoch 175/200 - Train Loss: 0.0789, Train Accuracy: 0.8771, Validation Loss: 0.0708, Validation Accuracy: 0.9065\n",
      "Epoch 176/200 - Train Loss: 0.0789, Train Accuracy: 0.8771, Validation Loss: 0.0708, Validation Accuracy: 0.9065\n",
      "Epoch 177/200 - Train Loss: 0.0789, Train Accuracy: 0.8778, Validation Loss: 0.0708, Validation Accuracy: 0.9065\n",
      "Epoch 178/200 - Train Loss: 0.0788, Train Accuracy: 0.8764, Validation Loss: 0.0707, Validation Accuracy: 0.9065\n",
      "Epoch 179/200 - Train Loss: 0.0788, Train Accuracy: 0.8750, Validation Loss: 0.0707, Validation Accuracy: 0.9065\n",
      "Epoch 180/200 - Train Loss: 0.0788, Train Accuracy: 0.8757, Validation Loss: 0.0706, Validation Accuracy: 0.9065\n",
      "Epoch 181/200 - Train Loss: 0.0788, Train Accuracy: 0.8757, Validation Loss: 0.0706, Validation Accuracy: 0.9037\n",
      "Epoch 182/200 - Train Loss: 0.0788, Train Accuracy: 0.8764, Validation Loss: 0.0706, Validation Accuracy: 0.9065\n",
      "Epoch 183/200 - Train Loss: 0.0787, Train Accuracy: 0.8764, Validation Loss: 0.0705, Validation Accuracy: 0.9065\n",
      "Epoch 184/200 - Train Loss: 0.0787, Train Accuracy: 0.8764, Validation Loss: 0.0705, Validation Accuracy: 0.9065\n",
      "Epoch 185/200 - Train Loss: 0.0787, Train Accuracy: 0.8757, Validation Loss: 0.0705, Validation Accuracy: 0.9065\n",
      "Epoch 186/200 - Train Loss: 0.0787, Train Accuracy: 0.8757, Validation Loss: 0.0704, Validation Accuracy: 0.9093\n",
      "Epoch 187/200 - Train Loss: 0.0787, Train Accuracy: 0.8757, Validation Loss: 0.0704, Validation Accuracy: 0.9093\n",
      "Epoch 188/200 - Train Loss: 0.0787, Train Accuracy: 0.8757, Validation Loss: 0.0704, Validation Accuracy: 0.9093\n",
      "Epoch 189/200 - Train Loss: 0.0786, Train Accuracy: 0.8757, Validation Loss: 0.0704, Validation Accuracy: 0.9093\n",
      "Epoch 190/200 - Train Loss: 0.0786, Train Accuracy: 0.8757, Validation Loss: 0.0703, Validation Accuracy: 0.9093\n",
      "Epoch 191/200 - Train Loss: 0.0786, Train Accuracy: 0.8757, Validation Loss: 0.0703, Validation Accuracy: 0.9093\n",
      "Epoch 192/200 - Train Loss: 0.0786, Train Accuracy: 0.8757, Validation Loss: 0.0703, Validation Accuracy: 0.9093\n",
      "Epoch 193/200 - Train Loss: 0.0786, Train Accuracy: 0.8757, Validation Loss: 0.0702, Validation Accuracy: 0.9093\n",
      "Epoch 194/200 - Train Loss: 0.0786, Train Accuracy: 0.8764, Validation Loss: 0.0702, Validation Accuracy: 0.9093\n",
      "Epoch 195/200 - Train Loss: 0.0786, Train Accuracy: 0.8764, Validation Loss: 0.0702, Validation Accuracy: 0.9093\n",
      "Epoch 196/200 - Train Loss: 0.0785, Train Accuracy: 0.8757, Validation Loss: 0.0701, Validation Accuracy: 0.9093\n",
      "Epoch 197/200 - Train Loss: 0.0785, Train Accuracy: 0.8757, Validation Loss: 0.0701, Validation Accuracy: 0.9093\n",
      "Epoch 198/200 - Train Loss: 0.0785, Train Accuracy: 0.8757, Validation Loss: 0.0701, Validation Accuracy: 0.9093\n",
      "Epoch 199/200 - Train Loss: 0.0785, Train Accuracy: 0.8750, Validation Loss: 0.0701, Validation Accuracy: 0.9065\n",
      "Epoch 200/200 - Train Loss: 0.0785, Train Accuracy: 0.8743, Validation Loss: 0.0700, Validation Accuracy: 0.9065\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+0AAAHQCAYAAADUPItJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAC710lEQVR4nOzdd3iUVdrH8e+U9IQUIIRACKH3HopSBUVkQcWCiCugKCAori6urq9dQdcVLKviAoKigMqKBUVABRSlG2rohN4CpJKQMvO8f0wyECENMjNJ+H2ua66Zp51zP0OZuec0k2EYBiIiIiIiIiJS7pg9HYCIiIiIiIiIXJqSdhEREREREZFySkm7iIiIiIiISDmlpF1ERERERESknFLSLiIiIiIiIlJOKWkXERERERERKaeUtIuIiIiIiIiUU0raRURERERERMopJe0iIiIiIiIi5ZSSdpEiDBw4kHr16nk6DCnG8OHDMZlMFz1GjhzpthhmzZpF3bp13VafiIh41vLlyzGZTGzcuNHToZR7s2bNuuTndIMGDdwWw/79+zGZTOzfv99tdYqUFaunAxApr3Jzc1m+fDlpaWns3buX+vXrezokKUKjRo349NNPC+yrXr26h6IRERGRP1u2bBmBgYHObV9fXw9GI1JxKGkXKcTq1atJS0vD29ubJUuWMGbMGE+HJEXw8/OjQ4cOng5DRERECtGmTRtCQkI8HYZIhaPu8SKFWLp0KfXq1aN///4sXbrU0+GIiIiIiMhVSEm7SCGWLl1Kr1696NWrF8uWLcNmsxU4/u2339KyZUv8/Pxo3rw58+bNK3D8yJEj3HbbbQQGBlKzZk3Gjh1Lenq687jJZGL58uUFrqlbty6zZs26aHvlypX06tWLFi1aFDh/9+7d3HTTTQQHB1OjRg0efPBBMjMznccNw2DSpElERUURFBREjx492LBhg/N448aNGTduXIEyH3jggRK3WJ89e5aAgADmzp1bYH/Hjh35+9//7txevXo111xzDYGBgdSqVYvnnnuuROWXleeff54WLVrwz3/+k5CQEOrUqcMrr7yC3W53npOTk8M//vEPatSoQWBgIHfeeScnTpwoUE5xf+YAO3fupHv37vj7+9OqVSvWr1/vPJaWlsZ9991HjRo1qFKlCv379+fgwYOuu3EREfG4jz76iIYNG+Lr68s111zDunXrChwv7jPy2LFj3HbbbVStWpXQ0FCGDBlCUlJSievv2bMno0aNKrDviSeeKPBZf6V1XKn8+QHef/996tSpQ1hYGMOGDSMlJaXAecW9l/Hx8Vx//fX4+flRp04dnnnmGXJzcwuck5aWxr333kuVKlWoXbs2H330UYHjr732GnXr1sXf35/27dtf9F1NxCMMEblIcnKyYbFYjNmzZxubN282AOP33393Hl+0aJFhMpmMhx9+2Fi+fLnxzDPPGCaTyfj5558NwzCM9PR0o0GDBkabNm2MhQsXGl988YURGRlpDBs2zFkGYCxbtqxAvdHR0cbMmTMLbD/wwANG1apVjQkTJhgfffSR85jdbjcaNWpkXHPNNcZPP/1kfPXVV0bNmjWNF1980XnOk08+afj7+xtvvfWWsWzZMuOWW24xqlatapw6dcowDMN46aWXjPDwcCM3N9cwDMPIzs42wsLCjLfeeqvE79Wdd95p3H333c7t48ePGyaTyVi3bp1hGIaRk5NjVK1a1ejXr5+xYsUKY/r06Yavr68xd+7cEtdRnGHDhhnARY9Vq1YZhmEYzz33nGEymYxOnToZixcvNl5//XXDarUWuM9hw4YZISEhxvTp041vv/3WaN68udG8eXMjMzPTMIzi/8xnzpxpVK1a1ahbt67xyiuvGEuWLDFatmxptG/f3lnH+PHjjbCwMON///uf8f333xtdunQx+vbtW2bvg4iIuM+yZcsMwIiLiyv0nJkzZxpms9l4+umnjaVLlxqDBg0yAgICjO3btxuGUbLPyJtvvtmoV6+e8f333xsLFiwwGjVqZIwaNarEcb733ntGrVq1Cuxr2rSp8frrr5dZHcWZOXPmJT+nJ02aZBjG+fcyIiLC+Pzzz4158+YZERERxq233lqgjKLeyyNHjhhVq1Y1evfubSxdutSYNWuWERgYaDz33HOGYRhGQkKCARitW7c27r33XuPHH3807rrrLsPHx8dITEw0DMMwFixYYADG5MmTjZ9//tm47777jODgYOPcuXNl9l6IXA4l7SKXkP+f9qFDhwy73W5Uq1bNeOGFF5zHr732WqN3794FrnnwwQeN2bNnG4ZhGNOmTTMsFouRkJDgPD5nzhzjvvvuc26XNGn39vY21qxZc1GM6enpxrRp04x9+/YZhmEYubm5xsCBA41+/foZhmEYaWlpho+Pj/HSSy85rzl27Jhx2223GX/88YdhGI4PMJPJZPzwww+GYRjG999/b3h5eRknT54s6VtlfPnll0ZYWJgz8Z8xY4ZRv3595/EzZ84YgPHBBx84961YscLYsWNHiesozrBhw4xGjRoZcXFxBR5nz541DMORtJvN5gJ/Hvfee6/RoEEDwzAMY+/evYbJZDJmzJjhPL57927DYrEYs2bNMgyj+D/z/C8kb7zxhvP4559/blitVuf2wIEDjS5duji39+7da/z4449l9C6IiIg7lSRpj46ONv761786t7Ozs4369esbw4cPNwyjZJ+RrVq1MoYMGeLc3rp1q/Hbb7+VOM6TJ08aFovF+dmf/5l34MCBMqujOPmfkb/88kuBz+kTJ04YhnH+vfz444+d13z44YfO72KGUfx7+fTTTxuhoaFGSkqK85y33nrLePLJJw3DOJ+0DxgwoMB7AxgrV640DMMwJk+ebHh5eRnp6emGYTgacb799lvn9wkRT9FEdCKXkD+GPSoqqsC+Z599FoA//viDJ554osA1H3zwgfP1H3/8Qe3atQssATZkyBCGDBlSZL0XdtfOd//999OxY8eL9gcEBNC/f39mzZrFsmXLWLt2LWlpaXTr1g1wdBHLysqia9euzmsiIiKYP3++c7tu3bp07dqVuXPn0rdvXz777DNuvPHGUs263q9fP3Jzc/n999/p1q0bCxcuZPDgwc7joaGh3HXXXYwfP57vv/+eTp06ccstt9C4ceMS11ESfn5+tGnTptDjtWrVKvDnERsby5w5c8jNzWXDhg0YhsF1113nPN6gQQOio6NZt24dw4YNK/bPHMBsNheYsLB69eoFuuWNHDmS22+/ndjYWLp160avXr3o37//Zd6xiIiUZ4mJiRw4cKDAZ4uXlxc9evRgzZo1QMk+I0ePHs24ceM4cuQIXbp0oW/fvvTq1avEcVSvXp3rrruOhQsX0rZtWxYuXEiXLl2oU6dOmdVRUi1btixyIrprr73W+To2NhaAvXv34uPjU+x7+ccff9CqVSuqVKniPOeRRx65qI4LhwXmf9/JyckB4LbbbuPVV1+lRYsW9OnTh2uuuYbbb78df3//y7hbkbKjMe0il7B06VKGDh1KXFwccXFxPPfcc87Z5MExVvzPdu3axaZNmwo9npyczMqVKwuMOb9Qbm4ux48fv2j/pRJ2gIMHD9K8eXN++OEHbr75Zn744Qeefvpp5/FLxQCwbt26AmuU/vWvf2XBggWkpqby9ddfM2zYsEteVxhfX19uvvlmFi5cSHZ2NkuXLi2QtAPMnTuXxYsX06FDB7777jtatGjBV199Vap6rtSf3w+73Y7JZMJsNhf6Xl14XXF/5gCRkZH4+fkVWtaAAQPYtWsXDzzwAImJidx5553ccccdpb0VERGpAEry2QLFf0aOGTOGbdu2cfvtt7N7926uv/56Hn/88VLFctddd7Fw4UKAi35cL6s6ysKF70t+Q8aVfE6fOHGClStXFmgUKWoJ3zp16rBr1y5effVVfH19efrpp2ndujWpqamlvheRsqSkXeRPDhw4wO7duxkwYABt2rShTZs23HHHHeTm5rJs2TIA2rZty6+//lrgugceeIAXX3zRefzw4cMFkuMFCxbQvXt356+5FouFjIyMAsfzj5XEggULSE9PZ+nSpYwdO5bOnTuza9cu5/FmzZrh7e1dIM5z587RrVs3vv32W+e+O+64g6ysLB555BFMJhMDBgwocQz5Bg8ezMKFC1m+fDlRUVG0atXKeWzz5s08/fTTdO/enf/7v/9j5cqVdO7cmZkzZ5a6nitx5MgR9uzZ49xes2YN9erVw2w206FDB0wmk/PPFxy/7B84cMD5S39xf+bg+DMtypNPPkl6ejoPPvggs2fP5u233+bLL79062Q/IiLiHuHh4dSpU6fAZ0tubi6//PKL87OluM/IjIwMHn30UYKDg3n44Yf53//+xz/+8Q+mT59eqlhuvfVWNm/ezN69e1m5cmWBH4zLqo6ysGLFCufrNWvWYDKZaNCgQYney7Zt27J58+YCCfZ7773HzTffjNl8PuUp6rN6+vTpLF++nMGDB/POO++wYsUKEhIS+Omnn8ryNkVKTd3jRf4kv2t8fjdzcCTA1apVY+nSpQwcOJCnn36aAQMG8MgjjzBo0CB++eUXfv31VxYtWgTA3Xffzauvvsqtt97KK6+8QkZGBs8//zx33XWXs9tW69atmTVrFtdffz0bNmzgySefJCAgoMRxVqtWjZycHGbMmEGjRo2YOXMmn332mbNrWVBQEOPHj+fVV18lODiYli1b8v777xMQEMDtt9/uLCckJIQBAwbw0UcfMXr0aLy9vUv9nt1www3ce++9vPnmmxf9eh8UFMS///1vvLy8uP766zl8+DDx8fEMHz7cec6WLVsICQkpMByhtDIzMwvM1A5gtVqdXeYtFgtDhgzhlVdeYePGjXz22We88847ANSrV497772Xxx9/HMMwCA8P55///CdNmjThrrvuAij2z7wkNmzYwJo1a3jyySfx8fHh888/p2rVqgQHB1/2fYuIiGetWbOGU6dOFdjXuHFjoqKieOGFF7j//vuJjo6mR48eTJ06lWPHjvHkk08CxX9G+vv7891333HkyBHGjBlDbm4uixYtol69eqWKMTQ0lD59+vDwww/TqVMnatas6TxWkjr2799PRkYGzZo1u8x3yWHjxo0EBgYW2Ne8eXPn66effprAwEDsdjtPP/00d9xxhzPW4t7Lhx56iKlTpzJo0CD+8Y9/cPToUd555x1Gjx5d4vhOnDjBCy+8QFZWFrVr1+aLL74AICYm5oruW+SKeWAcvUi5dueddxoxMTEX7b/llluMRo0aObcXLFhgNG/e3PD19TVatmxpfPHFFwXOP3jwoHHLLbcY/v7+RmRkpDF+/HgjLS3NeXzdunVGixYtjMDAQKN9+/bGypUrLzkR3YXbF8rNzTXGjRtnhIWFGUFBQcYdd9xhPPPMM0ZwcLCRnJxsGIZh2Gw24+WXXzYiIyONwMBA47rrrrvkhDlfffXVRTPkl9b9999vAJecYG7hwoVGbGysERAQYFStWtUYNmyYkZqaWuA+x48ff9l1FzZ7fHBwsGEYjonomjdvbrzwwgtGSEiIUbVqVePpp582bDabs4zs7GxjwoQJRrVq1Qx/f3/jjjvuMI4fP16gnqL+zGfOnGlER0cXOD9/Yp18hw8fNu666y4jPDzc8PPzMzp37lymE/2IiIj75P8ff6nHlClTnOfNnDnTqF+/vuHt7W106dLloslli/uMjI+PN/r372+EhYUZgYGBRu/evY34+PhSxzt79mwDMKZOnXrRseLqGDZsmNG6detS15mvsNnjyZvIL/+9/PDDD406deoYfn5+xh133GGcOXPmonKKei+3bNli9O7d2/D19TWio6ONF154wcjOzjYM4/xEdBdOSmsYBScGzs7ONv7xj38Y0dHRho+Pj9GwYUNj+vTpl33fImXFZBhFDBIRkUrt6NGj7Nq1i6+++orFixezfft2T4fkEs8//zzz589n69atng5FRERE/mT58uX06tWLxMREqlWr5ulwRModdY8XuYodPnyYfv36UaNGDT755BNPhyMiIiIiIn+ilnYRERERERGRckqzx4uIiIiIiIiUU0raRURERERERMopJe0iIiIiIiIi5ZSSdhEREREREZFy6qqfPd5ut3P06FGCgoIwmUyeDkdERATDMEhLSyMyMhKzWb+vXyl91ouISHlTms/6qz5pP3r0KFFRUZ4OQ0RE5CKHDh2idu3ang6jwtNnvYiIlFcl+ay/6pP2oKAgwPFmValSxcPRiIiIQGpqKlFRUc7PKLky+qwXEZHypjSf9Vd90p7fTa5KlSr6IBcRkXJFXbnLhj7rRUSkvCrJZ70GyomIiIiIiIiUU0raRURERERERMopJe0iIiIiIiIi5dRVP6a9JAzDIDc3F5vN5ulQRJwsFgtWq1VjXkVERETczGazkZOT4+kwpBwry+/qStqLkZ2dzbFjx8jIyPB0KCIX8ff3p2bNmnh7e3s6FBEREZGrQnp6OocPH8YwDE+HIuVcWX1XV9JeBLvdTkJCAhaLhcjISLy9vdWqKeWCYRhkZ2eTmJhIQkICDRs2xGzWaBcRERERV7LZbBw+fBh/f3+qV6+u3EAuqay/qytpL0J2djZ2u52oqCj8/f09HY5IAX5+fnh5eXHgwAGys7Px9fX1dEgiIiIilVpOTg6GYVC9enX8/Pw8HY6UY2X5XV1NcyWgFkwpr/R3U0RERMT91MIuJVFW39X1jV9ERERERESknFLSLiIiIiIiIlJOKWmvZGbNmoXJZLrosXz58isue//+/ZfVFehyr7tcM2bMIDg4mNzcXLfVKSIiIiJSHl3N+cHzzz/PLbfc4vJ6XE1JeyVz9913k5SUxC+//AJAUlISSUlJdO3a9YrLrlOnDklJSW677nItWbKE1NRUVq9e7bY6RURERETKI+UHFZ9mjy8lwzDIzLG5vV4/L0uJfo3y9vbG29uboKAgAEJCQsosBrPZfFnlXe51l8Nut/PTTz/Rs2dPli5dWib/GYmIiIiIXIqncgNQfnA1UdJeSpk5Npo9u9jt9ca/2Bd/7yv/4xo+fDh169alQYMGvPTSSzz66KOMGTMGgN9++41x48axc+dOWrRowaxZs2jWrJnz2v379xMTE4NhGM59y5cvZ/jw4bz99ts8/PDDpKWl8eKLLzJu3Lgrum7z5s3cfffdHD16lGHDhrFo0SLGjh3Lww8/XOT9/fHHH9jtdu6//37effddXnjhBeexn376ib/97W8kJCTQtWtXpk2bRu3atYs8NmvWLGbNmuXsPvTne+nZsyfDhw/nzJkzvPXWW7z//vvcdNNNAHz99dc88cQTHD58mM6dOzN79mwiIyOLrO+ll15i9erVfPfddwDs2bOHFi1acOLECYKDg0vxJy0iHF4Pi56AnHOuKd9shmsfhZa3u6Z8KZdmrEzg83WHGNSuFqN61Pd0OCLiYZ7KDUD5QUnzg6LMnz+fp59+mtOnT3PXXXfx73//27k025QpU3j99ddJS0vjpptu4qOPPsLX1xfDMPjHP/7BzJkzyc3NZejQobzzzjsu7e6v7vFXocWLF/Of//yHf//73wwcOBBwtFDffvvtDBo0iH379tG9e3f+/ve/l6i806dP89prr/H999/z4osv8vjjj3PuXPFfkou6bvTo0QwZMoRly5YxY8YMZsyYwT333FNsmUuXLqVTp05cc801rFu3juTkZAASEhIYMGAAjz76KPHx8VSpUsX5H0BRx0rigw8+YOnSpXzwwQd06tQJcHQ7Gjx4ME899RR79uwhPDycl19+udj67rzzTn766SdSU1MBWLBgAX379lXCLnI5lj4LRzbAyW2ueRzfAj88CblZnr5TcaNT6VnsPJHG8VQX/RgkIuIBlTk/KMy6desYNmwYr732GitXrmT9+vU8+eSTAOzYsYMJEyYwb948/vjjD/bs2cNHH30EON6radOm8eOPP/LLL7/w9ddfs2TJksuOoyTU0l5Kfl4W4l/s65F6y8revXvZvXv3RYlgXFwcoaGhbN68meTkZHbu3Fmi8tLT03n//fdp3rw5DRs25OGHH+bEiRNER0df9nUbN25k1qxZNGrUiObNm3Pw4EGuvfbaYmNZsmQJPXv2pF69elSrVo2ff/6ZQYMGMXfuXLp168Z9990HwBtvvMHGjRsBijxW0vtfsWIF3t7ezn2BgYEcOHCA4OBg1q9fz9mzZzl58mSx9TVu3JgmTZqwcOFC7r77br766ivGjh1b4lhEJM+xzXDgNzBb4c6Pwcu/jCsw4KuxkHYUtn4JbYaUcflSXnmZHS0puTajmDNF5Grgqdwgv+6yUpnzg8JMnz6doUOHOieqe+ONN7j++uuZMmUKPj4+AGRnZxMTE8OaNWuc1/n5+QGQk5NDu3bt2LdvX5mtx14YJe2lZDKZyqQbiicNGzbson+QZrOZKVOmMGPGDOrVq0dUVBQ2W8nG54SGhtKqVSsAZ+J6YVeXy7muQYMGrFq1imrVqrF79+4C3XAKc/bsWX7//XfWrFnDlClTSE9PZ8mSJQwaNIhDhw5Rr14957m1a9d2do0v6tifZWRkXLRv9OjRBRL2/Pt48skn+eabb2jatClBQUHO97O4+u68806+/PJLevfuzaZNm5y/dopIKayZ6nhudjM06e+aOmLvh59fgjXvQ+u7wI2rZIjnWC2OL2a5druHIxGR8qAy5AZQefODohw6dIju3bs7t+vXr09mZiaJiYnExMTwwQcfOHvN3njjjbz99ttUr16dHj168MQTTzBixAiOHTvGHXfcwRtvvIG/f1k3EJxX8f+GSakFBARctG/58uVMnz6d7du3Ex4ezvfff8+GDRtKVF6VKlUuK47CrjMMg2bNmvHII4/wwAMPMG7cOFq3bl1seStWrMBisbB582asVitz5sxhxowZAERFRfHrr786z921axeDBw9mw4YNRR4zmUzYL/hidqn35FLv55w5c1i9ejUHDhwgMDCQ9957j88//7zYWMxmM4MHD2bixInMnTuXG2+8kcDAwGLvXaRUbDmw6wfIPuvpSC5PrQ5QrYHj9b4VkHas4HF7Lmz5wvG60xjXxdF+BPzyOhzbBL+9CUE1oWoDqN3BdXWKx1nU0i4ilVBlzQ+KUqdOHfbt2+fc3rdvH35+flSvXp2jR4/SoUMH1q1bR0pKCrfffjsvvfQSb7/9Nvv27WPQoEE89dRTHD9+nBtuuIGpU6fy2GOPXVE8RVHSLgCkpaUBkJyczO7du3nsscdK9GuYK+zcuZNff/2V3377jeDgYKKiokp03ZIlS7j22mtp0MDxZX7QoEE8/fTT7N27lyFDhvDKK68wa9Ysevfuzcsvv0x4eDhms7nIY7Vq1SI+Pp7U1FSysrL417/+VaJY0tLSMAyDM2fO8Ouvv/LSSy/RqFEjgCLrA8evfI0bN+b5559n2rRpl/EOihTjt7ccLcQVlV8Y/G0rHFoDs28t/LxaHSAq1nVxBFSFVnfCHx/Dj8879sWOVNJeyXlZ8pJ2u5J2EancKkN+AHDu3DkOHz5cYF9kZCQjR46kR48e3HTTTTRt2pTHHnuMUaNGYTKZ2Lp1K3/961/58ssvnV36c3NzAfjxxx958803+fTTT50z4OcfcxUl7QLAjTfeyI033ki7du2IiYnhgQce4Mknn+TEiRPUqFHDrbE0atSI8PBwevToQUpKCl5eXgwbNoypU6cWed3SpUsLTEbRpEkTIiMjWbJkCWPGjOHrr7/mscce45FHHqFnz57MnDkTgJiYmEKPXXfdddxwww20bNmSGjVq8M9//pO777672HsYNmwY3333HU2bNqVly5aMGjWK9957j3PnzhVZX77Bgwfz4osv0r+/i7r1ytUrNxvW/tfxunZH8AnybDyldWwjZJyGTXNhx/eOfdWbQJVaBc+z+kD3kk2Wc0V6PgXnUiHL8cWGao1dX6d4lDXvB9Ycm7rHi0jlVhnyA3BMHPfnJD8xMZEOHTrw0Ucf8Y9//IPTp08zePBgJk2aBMANN9zAqFGjuOOOO0hOTuaaa67h//7v/wAYMWIEcXFx9O3bl8zMTG644QYeeuihsr/pC5gMT/1cUk6kpqYSHBxMSkrKRd0xzp07R0JCAjExMc6p/8X1ZsyYweeff8706dPx9/dn8+bN3HTTTZw4ceKyu9pUJHv27GHu3Lns2LGDTz/9tMhz9XdUSm3TZ7DgQUdX7ke3gMXL0xGVzuqp8MM/HPGnHQNM8EgchMV4OrIyVdRnk5ReWb6fs1ft55mvt9GvRQTv39O+jCIUkYpC3708o6LmB0X9fSnNZ5Na2qXc6dWrF3PmzKFFixZkZmYSHR3Nq6++Wq7/QZalNm3aEB4ezsKFCz0dilQ2hgGr33O8jr2/4iXsAG3uhp9fPj+OvXG/SpewS/kWknmI7uZNVMs8ByhpFxFxh6s9P1DSLuVOvXr1+Omnnzwdhsekp6d7OgRxp2Ob4Ivh57tXu5JhQMYpsPg4JlGriHyrQNt7HDO2A3Qa7dl45KrT8MiXfOz9IT+k3gbc5ulwRESuCld7fqCkXUTEk5ZNgjP7ij+vLLUfBgHV3FtnWeo8GjZ+CjWaQ0z34s8XKUMms+Ork8lw7aRDIiIi+ZS0i4h4ypl9jqXXAP66AALdMKmL2cuxLFlFFlrXMXu8xUdro4v75Q0rMduVtIuIiHt4JGnfunUrI0aMYM+ePYwcOZJ//etfmIr44pWTk8M///lPPvvsM3JycnjggQd49tlnsVod4c+fP5/HH3+cnJwc3njjDYYMGeKuWxERuXxr/gsY0OB6qH+dp6OpWHyDPR2BXKVMeUm7SUm7iIi4idndFWZlZTFgwADat2/P+vXriY+PZ9asWUVe88ILL7Bo0SJ++OEHvv/+ez799FNeeOEFwPEDwNChQ3nmmWdYvHgxzz77LDt37nTDnYiIXIFzqRD3ieN1Z43LFqkw8pN2w+bhQERE5Grh9qR90aJFpKSkMHnyZOrXr8/EiROZMWNGkdd8/PHHvPDCCzRr1oy2bdvy+OOP8/XXXwMwffp0evXqxciRI2nZsiXjxo1j9uzZ7rgVEZHLt3EOZKdBtUZQv7enoxGREjJbHL38LEaOhyMREZGrhduT9k2bNtG5c2f8/f0BaNWqFfHx8UVec+rUKerUqePctlgsWCwWZ3nXXXe+W2nHjh3ZsGFDoWVlZWWRmppa4CEi4lZ2O6z9wPG60yiNyxapQPK7x5s1EZ2IiLiJ25P21NRUYmLOr6lrMpmwWCwkJSUVek27du2cLes2m43Zs2dz/fXXX7K8KlWqcPTo0ULLmjRpEsHBwc5HVFTUld5SuTJr1ixMJtNFj+XLl3sspmeeeYZmzZp5rH6Rcmf3EsckdL7B0FpzcEjltHXrVmJjYwkNDWXChAkYhlHia5OTk6lZsyb79+8HwDAMQkJCCnyuvfzyyy6KvGhK2kWkoilP+cHw4cN59NFH3V5vRef2pN1qteLj41Ngn6+vLxkZGYVe8+677/LRRx9xww030KhRI9asWcOYMWMuWV5xZT311FOkpKQ4H4cOHbrCOypf7r77bpKSkvjll18ASEpKIikpia5du15x2SaTyfkFqjSWLFnC9u3bOXz48BXHIFIprJnqeG53L3gHeDYWERe4nPlrLjRhwgSOHz/u3N69ezchISHOz7SkpCQmTJjggsiLZ3Ym7RrTLiIVQ3nMD6R03D57fFhYGFu3bi2wLy0tDW9v70Kvad26Nfv372fHjh389a9/ZcSIEc7W9bCwMBITE0tclo+Pz0U/GpSKYUBO4T8KuIyXf4m60Hp7e+Pt7U1QUBAAISEhLg6saElJSWzcuJGuXbuydOlSRowY4dF4RNwmJxNm3ADHN1/6uMkMHR90b0wibnLh/DX+/v5MnDiRsWPHlugz4JdffuGbb76hatWqzn3r1q2jS5cuHv9MAzBZlbSLyAU8lRtAhc0PpPTc3tIeGxvLqlWrnNsJCQlkZWURFhZW5HUWi4WMjAx27tzJ888/X2h5cXFx1KpVq8zjdsrJgImR7n+U0X8G69ato1OnTgQHBzNo0CBSUlKcx+bOnUtMTAwBAQH07duXU6dOAdCkSRPnknwxMTGYTCbmzZtXovp++uknmjZtyo033siSJUsKHJs7dy4NGzYkODiYu+6666JYLnXs+eefZ/jw4c7zli9fTt26dZ3bdevW5ccff+Spp54iIiKCbdu2OY9NmzaNOnXqEBQUxKBBg0hPTy+2vvvvv5+xY8c6z/vxxx+JjIzEbreX6P7lKrb588ITdoA2QyGkTuHHRSqwy5m/Bhwt9KNGjeLtt98mMDDQuX/t2rWsXbuWkJAQwsPD+b//+78iu9u7cv6a/JZ2i7rHiwh4LjeowPlBUd59913q1q1LzZo1ef75553fuQ3D4IknnqB69eqEhoYybtw45+dAdnY2w4cPJzQ0lPDwcCZOnHjFcZQ3bk/au3fvTmpqKjNnzgRg4sSJ9OnTB4vFQnJyMjZb4b9cP/vsszz++ONERkY69912223MmzePLVu2kJ6ezttvv03fvn1dfh8VUXJyMv369aNfv35s3ryZ1NRUHn/8ccDRQ2HYsGFMmjSJbdu2YbVaeeONNwDHP+T8OQc2bdpEUlISt912W4nqXLp0KV26dKFLly78+OOPzn9cv//+OyNHjuSNN95g48aNHDt2jOeee67YYyXxzDPPcPjwYT799FNnQr9t2zbGjBnD9OnTiY+P5/Tp07z33nvF1nfnnXfy1VdfOeNesGABd9xxB2az2//pSEViGOe7wF/3DEzYW/DxRAIMfMezMYq40OXMXwOO7wSNGjVi8ODBBfbv2rWLAQMGEBcXx5w5c5g6dSqfffZZoeW4cv4as1raRaQS8UR+UJj//e9/vPDCC8yaNYvvvvuOTz/9lLfffhuAxYsXM23aNH788Ud++eUXvv76a2eD4Icffshvv/3G2rVr+frrr3nllVfYsWPHFcVS3ri9e7zVamX69OkMGTKECRMmYDabnZMghIaGEhcXR5s2bS66bsWKFWzcuJEvvviiwP7WrVszfvx4OnTogK+vLw0bNuShhx5y3Q14+cM/C5/ozqX1XqHvvvsOLy8vnnvuOUwmE3//+9+59957Acefi9VqJTs7m5o1a/LNN984f9nK70oDjon+StOlZunSpTz33HN07NiRpKQk4uLiaNeuHbNmzeKee+5h4MCBAPz3v/91TiBY1LGSCA4OvmjZv/r163P8+HF8fX1Zs2YNOTk57Ny5s9j6evfuTVZWFqtWraJLly58/fXXfP755yWORa5SCb/AyXjwCoDYkeAX4umIRNyqqPlrQkNDL3nN9u3bmTp1KnFxcRcdW7RokfN1TEwMjzzyCPPnz+euu+66ZFlPPfUUjz32mHM7NTW1zBJ3Z0s7amkXETyXG+TXfYU8kR8U5r///S+PPvooPXv2BBw9bF966SUeffRR/Pz8AMjJyaFdu3bs27fP2Yjm5+eHYRjk5ubSpUsXkpKSsFrdnua6lEfuZuDAgezdu5cNGzbQuXNn57i1orq69ejRg2PHjl3y2CuvvMLQoUM5cuQIPXr0KHJM+xUzmSrsxFGHDx8mMTHR+YXJbreTlpbGuXPn8PPzY968efzrX//i4YcfpmvXrrzzzjvUq1fvsuvbvXs3CQkJjB07lvHjx2O321myZAnt2rXj0KFDzn+QAI0bN6Zx48YARR77s0tNOvjwww9ftC8zM5MHHniAX3/9ldatW2OxWJy9Ooqqz2q1MmjQIL788kusVitms5kuXbqU9q2QiiI7A1a9C1kpYPGG9iMgpIgv+oc3QPxXwJ/+79q3wvHcZogSdrkqlXb+GsMwePDBB3n55ZcL9KYrTHh4OEeOHCn0+BXPX1OE/KTdqu7xIgIVOjcA9+cHRTl06FCBsuvXr8/BgwcBRy74xBNPMGLECI4dO8Ydd9zBG2+8gb+/P0OGDGHbtm0MHDiQs2fPMmzYMF555RWXxOgpHuvjGxERQf/+/QtMNHMlmjVrxvXXX+/ahL2Cq127Nu3bt2fjxo1s3LiRTZs2ERcXh5eXF2fOnKFGjRqsXLmSEydOUK1atYuWYzCZTKVasmfp0qXUrVuXrVu3snHjRkaPHs3SpUsBiIqKKjDT5LJly+jXr1+xx0wmU4Hx5Bs2bLio3oCAi//jfOutt0hJSeHYsWP89NNPBRLvouoDGDx4MF9++SVfffUVd955p3P8jlRCv70Jy16G39+BX9+A7x4v/NzcbJh3N/z+tuP8Cx/5Y9k7jnJL2CLlTWnnrzl48CArV65kwoQJhISEEBISwsGDB2nVqhWffvopLVu2JDMz03n+qlWriI6Odvl9XIrZK7+lXd3jRaTic3d+UJQ6deqwb98+5/a+ffuc/9fv27ePQYMGsWXLFrZu3cpvv/3G1KmOoYh79uxh7Nix7N69m19//ZVZs2bx1VdflUlM5YUG5l5F+vfvz8GDB1m7di1+fn7Mnz+fG2+8EcMwOHnyJD179uSHH37gzJkzAOTmFmxFqF+/PosWLeLIkSPOJSOKsmTJEvr06UPdunWpW7cuAwcO5LfffiMjI4MRI0Ywe/ZsFi5cSEJCApMmTaJOHcekXEUdq1WrFhs2bCAnJ4c9e/bwwQcflOje09LSsNvtJCYmMmfOHN5//33nfzBF1QfQs2dPzp49y3vvvXfROEupRHKzYP2HjtfNBwEm2L0YTu+99PnxX0P6cQioDtc8cvHjzo+heiO3hS9SnpR2/ppatWqRkJDg/NK4ceNGIiMj+f7777n55pupUaMGDz30EOvXr2fKlCnMmTPHufSru1msjsYBjWkXkcrA3fkBQHp6OocPH3Y+8oelPvDAA7z55pusWLGCuLg4nnvuOUaPHg04JoO+9dZbiYuLc/6Imx/LJ598wvDhw4mPjycrK+uScVZ4xlUuJSXFAIyUlJSLjmVmZhrx8fFGZmamByK7MnFxccal/njXrl1rdOzY0fD39zdiY2ONNWvWOI+9++67Rt26dQ1fX1+jU6dOxtatWwtcu3TpUqNevXqGl5eXcffddxdZf05OjlGlShVjzpw5zn3p6emGl5eX8f333xuGYRhz5swxGjRoYISEhBh//etfC/wZFHYsPT3duP76642YmBija9euxtSpU43o6GjnddHR0cayZcsuiufgwYNG586djYCAAKNPnz7G+PHjjVatWhVbX74xY8YYMTExRd6zJ1Tkv6PlTtynhvFcFcN4o6lh5GYbxid3OLa/m3Dp8//by3F8+WvujVOuCkV9NlUUX3/9teHv729UrVrVqF69urFt2zbDMAwDMOLi4oq9Pjo62khISDAMwzAOHDhg9OrVy/Dx8TEaN25szJ8/v1SxlOX7mRy/zDCeq2LseaaxYbPZr7g8EalYKvJ3L0/nB4ZhGMOGDTNwjCt0PgICApzH33nnHaNOnTpGRESE8dxzzxk2m80wDMPIzs42Ro8ebVSvXt0IDAw0Bg0aZKSlpRmGYRjJycnGnXfeaYSEhBjBwcHGgw8+aOTk5FzWe1TWivr7UprPJpNhlFF/hgoqNTWV4OBgUlJSqFKlSoFj586dIyEhgZiYGHx9fT0UoXhSZmYmiYmJvPzyy1SvXr3cjY/R39EyYhjwQXdHt/bez0G3x2DvzzD7VvAOhDG/FZzs5cRWxzGLN/wtHgKrey52qZSK+myqSI4fP37R/DWeUJbvZ/ru3wn8tB8H7dWJeHYX3lZ1WhS5mui7l5RGUX9fSvPZVLmm1RMpY2fOnKFRo0Y0btz4onXmpRI5uMqRsFv9oP1wx756vaB6E0jcAW+1vvR1Le9Qwi5ShPz5ayoTS/6YdpOdXLsdb400FBERF1PSLlKEWrVqce7cOU+HIa62+n3Hc6s7wT9voiyTCXo9DQtGQU7mxdcEVINrH3VbiCJSPljy1mn3wkau/arurCgiIm6ipF1Erm7JB2HHQsfrTqMLHms20PEQEcljzZuIzkouuTYl7SIi4nrq01UCV/mwfynH9HezDKydBoYdYnpAjWaejkZEyjmzM2m3kWuzF3O2iFRW+g4mJVFWf0/U0l4Er7xxaxkZGfj5+Xk4GpGLZWRkAOf/rkoJ2W2w4l+QtB92fu/Y9+dWdhGRS7E4vjpZsZOj7vEiVx2LxQJAdna28gMpVll9V1fSXgSLxUJISAgnT54EwN/fH5PJ5OGoRBy/2mVkZHDy5ElCQkKcHyBSQvFfw4pXz2+H1YNGfT0Xj4hUHOb8pD0Xm7rHi1x1rFYr/v7+JCYm4uXlhdmsjstysbL+rq6kvRgREREAzsRdpDwJCQlx/h2VUlgz1fHcdADU6QIN+4JZP3yISAmYHa0l3iYbOTabh4MREXczmUzUrFmThIQEDhw44OlwpJwrq+/qStqLkf8PMzw8nJycHE+HI+Lk5eWlFvbLceQPOLTG8cX7pjcgqIanIxKRisRyvotjbm6uBwMREU/x9vamYcOGZGdnezoUKcfK8ru6kvYSslgsSpBEKoLcLDi9BwwDgmpCQNWCx/Nb2VsMUsIuIqVnPv/VyZarL+wiVyuz2Yyvr6+nw5CrhJJ2Eak8DANm3woHfnNsewfB2NUQXNuxnXYctn7peK2J50TkclyYtKsHnoiIuIFmThCRyuPQGkfCbjKDlz9kpzmWdMu3/kOw50BUJ6jVznNxikjFdUH3eJtNLe0iIuJ6StpFpPJY/b7juc3dMCgvWd8wC7IzHN3m13/o2KdWdhG5XBe0tOeqpV1ERNxA3eNFpHJIOQzbv3W87jQGwptCSDQkH4DNn4HVB84mQlCkY9Z4EZHLYTJhw4wFO4ZNSbuIiLieWtpFpHJYOw0MG9TtBhEtHEu4dXzQcWzZK/Dj847XHUcW6N4qIlJauXltHrYcdY8XERHXU9IuIhVfdgb88ZHj9YVd39v9FXyCHS3s6SfAOxDaDfdIiCJSedhMjtVkbLlqaRcREddT93gRqfi2fA6ZSY7u8I37nd/vGwwjf4SjcY7tmq0vXgJORKSUbHlfn+w2rdMuIiKup6RdRCo2w4DVeWuvd3zQ0S3+QtUbOR4iImXEZrKAAXbNHi8iIm6gpF1EKqbcLDi0FhJ3QOJ28AqAtvd4OioRuQrYTXkt7eoeLyIibqCkXUQqpu8nnB/HDo5l3vxCPBaOiFw9nN3jlbSLiIgbKGkXkYon/SRsmut4Hd4c/MOg6988G5OIXDXyJ6LTkm8iIuIOStpFpOJZ/yHYsqFWB3jgJ09HIyJXGSO/e7ySdhERcQMt+SYiFUtuFqyb4XjdeYxnYxGRq9L5lnZNRCciIq6nlnYRKR9yMuF/IyHpQNHn5WbC2ZMQVBOa3eye2MTtTqdnkZFtIyrM39OhiFzEbnZ8fTK05JuIiLiBknYRKR92L4UdC0t+fueHwOLlunjEJQzD4HBSJtk2eyHHYeHmo0xdsZdcm8H0YR3o2TjczVGKFC2/e7ySdhERcQcl7SJSPhxe53hu8heIvb/oc70CoHas62OqRHJtdnLthnPbbDLhbXXtCKk/17n7RDovLYxn7f4zJS5j7Kd/8MXoa2gWWeWSx212g5wLfgAwmcDHarn8oC9gtxvOHxd8rGZMJlOZlCsVX/6Sb0auuseLiIjrKWkXkfLhyAbHc+N+UP86z8ZSiWRm25i6Yi/Tft1HRrbNud9sghdvbsE9naNdUu/ynSf522cbScq4eKIuq9lEgE/hHz/hQT483Lshc9ccZNW+09w3ax1fjb2WiGBf5zlZuTZm/bafd5ftIfVcwdbO3k3Cebp/U+pVD7ys2O12g683HeH1H3ZyNOUcAE0ignjmL824tkG1yypTKhcjv3u83VbMmSIiIldOSbuIeJ4tF47GOV6rBb3U0rNy+dtnG9lwIOmiY5nZNjJzLk4s7Aa8/dNu7uwQVeYt7vFHUxn76R+czS5Yr8kEf2kVyVP9mhAZ4ldsOT0aVee2939nz8l0Rsxax2PXN+I/y/Zw6EwGWTm2i8rP99OOkyzflUiw3+UNn8i12S/6IWDH8TSGTl9DqL+Xs8XdbDLRp2k4j9/QmOpBPpdVl1RM+S3t2NXSLiIirqekXUQ872Q85GSATzBUbejpaCqUXJudcXP+YPnOxELPqRXix9P9m9KjUXXHNXaD6yev4GRaFou2HuPmNrWc52Zk5/LBin38cTCJB7vXo3lkMG//tJv1B0repf3g6QzOZtvoUq8qU//aHqvZkeRazCZ8vUredT3Yz4uZw2O59b3f2H4slQc+Xl/gePUgH568sQl9W0SQ33H9aHImkxbt4OcdJzlz9vITKn9vC+Oua8DQTtFk5dp4f/lePl514KKeA/PWHeK7zcd4pHdDhl1T1+VDDqScyGtpR2PaRUTEDZS0i4jn5Y9nr9UWzEp6irJoyzG+3ngUu+EYK56YnkXcwWR8vcy8P7Q9tUMLtmCbTBBdNQAvS8H39Z7O0UxeuosPf9uPr5eFbzYdJSfXzubDKRxPdXQJ/3X3KXy9zJzLufSkcUVpGB7I1L+2v+zW7nxRYf5MHxbLkP+uJttm594u0QyOjcJiMlGnqv9F49cb1gjiw+GxHE7KILOQlviSiAj2Jcg3P3YvnhvQnHG9GhT4IeB46jn+9cNOthxJ4ZXvtzNn7UGe+UtTrmtS47LrlYrh/OzxWqddRERcT0m7iHhe/nh2dY0v0qItx3hozh8YRsH9JhO8dVdbejUp+SzrQzrW4T8/72HToWRGzd5Q4FjtUD+uqV+VL/84wrkcO01rVmFsr/oEFjEO/UIWs4nYumGlalUvSpuoEH56vAdAibrVA9QOLful4qoG+lA18Hw3+IY1gri2fjXm/3GYf/2wk4RTZ/nfH0eUtF8F8se0m+xqaRcREddT0i4inudsae/g2TjKob2J6SzbcZLMbBv/WbYHw4Bb2kTSMaaq85xWtYNpUSu4VOVWD/JhYJtI5m84jLfVzPBr6lK3agCBvlZuaFYDXy8Lo3vUZ1/iWXo1Ccdi9uzM6SVN1t3NbDZxZ4co+rWI4N1le7mncx1PhyTuYHb0wjCUtIuIiBsoaRcR97LbYf4IOLjq/L70E47n2ldf0p5js7Nm3xla1g4m2M+Ls1m5/LbnFNk2O+v3JzF79QFsFyyb1rtJOG/c2aZMkujnBzande1gejQKp07Vi1um61UPvOwZ2K82Qb5ePNmviafDEDdxtrSre7yIiLiBknYRca+9P0P8Vxfvrx0LAWW3nFZ6Vi4Z2bmEB/kWf3IewzDYczKdtKxc/LwsNIkIKrA2t81ucCQpk6gwv0uu2Z2ZbWP78VQAokL9nTOKH03OdI4Tv9DxlHP8e8lO9iWeJSzAm8GxUfxvw2FOpmUVOO+a+lWJqOJL7VA/RvWoX2at3oE+Vv7apW6ZlCVyVcmfiE4t7SIi4gZK2kXEvda873hudy90HHV+f7WymzX+ROo5Br33O8dSMhnaKZqR3WKKHV99MjWLfy3ewa+7Tzn3DWwdyZuD22A2m8ix2Rn50XpW7EqkW8NqPNG3CeFVfAjyteLvbeVIcia3v/87x/LW9fa2mBnZLYbUcznMWXMQu1FYzY4108+czeb95XsBiAz2JSrMnwAfK8OvqUv3vFnfRSqarVu3MmLECPbs2cPIkSP517/+dckfvC4lOTmZpk2bsmrVKurWrQvAu+++y4svvkhAQADTp0/nuuuuc2H0hTPyusdrTLuIiLiDknYRcZ/EXbDnR8AEXR+DsJgyr+JsVi73zVrHkeRMAGavPsDs1QdKfL2XxUREsC9Hk8/xzaaj1Ar144m+jXnmq62s2OVYVu3X3af4dfdKALytZu67NoZlO05yLOUcQb5WArytHE89x3t5STg4ll3788T4FpOJG5pHMLpHfb7eeIT//XGYm1rW5L5ri/+RQaS8y8rKYsCAAfTt25d58+bxyCOPMGvWLEaMGFGi6ydMmMDx48ed24sXL+bvf/878+bNo3r16txzzz2sW7eOqlWrFlGKa5jMef8+DXWPFxER11PSLiLFs9th8zzIOH1l5exd5nhu3K9ME3bDMHjh23jmrDlIjt2OYUDVAG+eHdCMGSsTiD+aWmwZZpOJXk2q88+bmhJdNYD/bTjM419s4v3le/lgxV7shqNF/MWbW/Dr7kSW7UjEZhhk59qZusKRnIcH+bBg7LVEBvuyNP4E/1q8E39vC0/1a0qX+kUnFiOujWHEtWX/I4aIpyxatIiUlBQmT56Mv78/EydOZOzYsSVK2n/55Re++eabAgn5+++/z7Bhw7j55psBuPnmm1mwYAEjR4686PqsrCyyss4PM0lNLf7/gNIwLHkt7VqnXURE3EBJu4gUL242fPtI2ZXXaXTZlQVMWbqLWb/vd26HBXgzfVgH2tYJ5eY2tS6rzNva1+ZE2jneWLILm93A22LmmQHNuKdzNPd0jgYcPxb8uP0kr3wXT0pmDh8Oj6VW3iznNzSP4IbmEVd8byIV1aZNm+jcuTP+/o5JDlu1akV8fHyx12VlZTFq1Cjefvtt/vGPfxQo7+6773Zud+zYkV9++eWSSfukSZN44YUXyuAuLs2U3z3esLmsDhERkXxK2kWkaIYBq/PGodftBlUuLwl2qtEMYrpfeVw4Zl7/7y/7ePvnPQC8fEsLbmhWgyp+XmXSvfyhng0Y2imarBwbft4Wgny9Chw3mUxc36wGfZqGk22z42NVl3aRfKmpqcTEnO89YjKZsFgsJCUlERoaWuh1EydOpFGjRgwePLhA0v7n8qpUqcLRo0cvWcZTTz3FY489VuDaqKioK7mdgvJb2u3qHi8iIq6npF1EipawAhK3g1cADP4E/EIuOmXn8TS+WH+IW9vVonlk6dYLz7XZ+eCXfQT7eTE4Ngovi7n4i4DlO0/y0sJ49iaeBWBsr/rOFvCyFOznBX5eRZ5jMpmUsIv8idVqxcfHp8A+X19fMjIyCk3at2/fztSpU4mLiyu2vPyyLsXHx+eiusuSyeL4+mTWRHQiIuIGStpFpGirpzqe29x9yYT90JkMhk5fzan0bD78LYHBsXX4+w2NqBpY/BdmwzB4/tttfLL6IAAzf0vgxhYRWEwm+rWsSdOaVZznJmdk8/n6Q6Rm5rL1aArLdzomhasW6M2Evo25s0MZtqKJyBULCwtj69atBfalpaXh7e19yfMNw+DBBx/k5ZdfJjIy8pLlJSYmlqgsl3N2j1fSLiIirqekXUQKd2Yf7PoBgF9Cb+XwmoMXnfLhbwmcSs8mLMCbM2ezmbv2IAs3H+XRPo24t0t0oS3nhmHwwS/7+GT1QUwmR4v23sSzvLvMManbFxsO89PjPfD3tpKZbWPYh2vZdDjFeb3VbGLEtXV5uHdDqvgW3RIuIu4XGxvLtGnTnNsJCQlkZWURFhZ2yfMPHjzIypUr2bJlCxMmTAAc3dpbtWrF1KlTiY2NZdWqVfTu3RuAuLg4atW6wuE6lym/pV1Ju4iIuIOSdhEp3Jr/AgaHq3Xl3m+SgeRLnhZRxZevxl7LwTMZvPDtNrYdTeWlhfHMWXOAh69rSIh/waQ6x2bw8ar9zjXRn76pKXd0iOLTNQc4mZrFD1uPcyzlHB+s2McjvRsyfl4cmw6nEOrvxc1tauHnbeH29rWpXz3QpbcvIpeve/fupKamMnPmTEaMGMHEiRPp06cPFouF5ORkgoKCsFjODyupVasWCQkJBcro2rUr8+bNo02bNgQGBjJ69GhGjBiB1WplxowZvPXWW+6+LQDMFkcLv7rHi4iIOyhpF5FLO5cKcZ8A8MqpHgB0jAkj5E/ju4N8vRjTsz4Rwb5EBPvyzbiufLH+EP9espO9iWd59LONhVbhbTUzvndD7u8ag8lk4qGeDZz1PPTpH0xdsZcft59g29FUvK1mpt3bgQ51L91KJyLli9VqZfr06QwZMoQJEyZgNptZvnw5AKGhocTFxdGmTZsC59etW/eiMmrXrk1gYCADBgzgiy++oGHDhgD07t2bQYMGuelu/iR/TLta2kVExA2UtItIATa7wbkcG9b1s/HJTuOkT10WpTSjSUQQc0Z2wlrMRHEWs4m7OtbhplY1eW/ZXn7bcwoD46LzGoYH8bc+jahT1f+iY/1aRNAxJoy1CWfYdjSVIF8rr9/eWgm7SAUzcOBA9u7dy4YNG+jcubNz3XXDuPj/hEvZv3+/87XJZGL27Nk88sgjnD17lh49emAymVwRdrFMebPHm7Xkm4iIuIGSdhEBHMn6Z+sOsXPxB9TM3s8AyypqmeCt9OsAE8/+pVmxCfuFqvh68WS/JpcVi8lkYuKtLfjbZ5toVTuYx64v2cR2IlL+RERE0L9//zIrLzY2tszKulxma37SrpZ2ERFxPSXtIleBw0kZvPbDTn7dnYjdblCjii/j+zSkf8uamEwmVu87zQvfxuN3fD1f+vzH+T9DiuHPl7au3NG+Ntc0qObWmBuEB/Htw13dWqeISEmY87rHW5S0i4iIGyhpF6nkvtl0lAlfbCIr1+7cl3ounXFz4vhX2E68rWb2nEwH4ANfx0zxtlodMaI64dvwRuLqdMHXS2uQi4jkc05Ep+7xIiLiBkraRSqxrFwbL367jaxcO51iwvh738aE+nuzcPNRpq7Yy8EzGQCYTTCmrQ83bF8HBlgGvgk1mus/CBGRSzDldY+3KGkXERE30HdykUrs203HOJWeTUQVXz4Z2cm5ZvqjfRoxtFM0O46nAhAdFkCdP14DwwZ1u0GN5p4MW0SkXLPkJ+2oe7yIiLieknaRSsowDGb+5ljz+K9dop0Je77qQT5UD6ru2MjNhj8+crzuPMadYYqIVDj5s8drTLuIiLhDyaeCFpEKZf2BJLYdTcXHamZIxzpFn3x8C2QmgV8YNLrRPQGKiFRQlvwl31D3eBERcT0l7SKVUGa2jZcXxgNwS5tahAV4F33BkfWO59odwKxJ50REimLxcvyfatWYdhERcQN1jxepRM6czSYzxzH53KbDKYT4ezHuugbFX3h4neO5tufXPxYRKe/M1ryknVwMw8BkMnk4IhERqcyUtItUEvM3HObvX2xybntbzEy7twNRYf6OHQm/wqa5YNghpA50fwLy1hrmcF5Le632bo5aRKTisVjz1mnHjs1uYLUoaRcREddR0i5SCdjtBu8u2wOAl8VEiL83Lw5sTmzdMMcJudnwv/sh/cT5i6o2gFZ3wtlTkOSYsE5Ju4hI8Sz5Le0mG7l2A6tGFYmIiAspaRepBFbsSiTh1FmCfK2sfqo3AT5/+qe9bYEjYQ+sAXW6QPxXsPp9aHkHHNngOKdaI/ALcXfoIiIVTn7S7kUuOTY7vl7K2kVExHU0EZ1IJfBh3tJud8VGXZywGwased/xOvYB6P8GWHzg6B+Osez5XeM1nl1EpESsXo7Z463YyLUZHo5GREQqO7W0i7iT3QaZyRBQtWTnZyZD6pFLHkrJzOGzdQc5lZ7NyT2JNDXD/Q0j4MS2giee2gVH4xyJeocREFDN0cK+8RNY+aZjqTdQ13gRkRIyW84n7dl2Je0iIuJaStpF3Gnx07BmKgydDw37FH1uxhl4pz1knrnk4WDgwbzX//TJezGniPJa3uFI2AE6j3Yk7Tu/O39cLe0iIiViuiBpz7DbPRyNiIhUdkraRdwl/SSsnwEY8Ou/i0/aN8x0JOxWX/AJcu42gLRzuWTl2jCbTPh5WTCZwMdqwVzYBMZ+YdDtsfPbES0hdiTEf+3YrtUBajS/krsTEbl6WNQ9XkRE3EdJu4i7rJ8JtmzH64Or4OhGiGxz6XNtObB2uuP1X6ZAm7udh15btIOpK/biZTEx+/5OdK5Xwq72f9b/DcdDRERKx+z4+mTFMXu8iIiIK2kiOhF3yM3Oa2UHgiIdz2umFn7+9m8g7SgEVIcWt5F6Loftx1KZ/us+pq7YC8C/bm91+Qm7iIhcPrOjpd1iMsjNzfVwMCIiUtmppV2kLKUdhx+ehHOpBfdnpeYtuRYBd8yED/vClvmOLvOXcjLe8dzhfjYcOcuwD9eRnnX+i+Hf+jTi1ra1XXQTIiJSJMv5r0+5OdkeDERERK4GStpFytKK1xxrohem0yio09mxVvrBVbD3p8LPtfpxqN5djPxoPelZuQT5WvHzsnBb+9o80rtB2ccuIiIlk9fSDmDLVdIuIiKu5ZGkfevWrYwYMYI9e/YwcuRI/vWvf2EyFTaDFhiGwUMPPcRnn32G3W7nlltu4f3338fPzw+AVq1asWXLFuf5999/P9OnT3f5fYgUkJkEm+Y5Xl/3DAT/qSXcOwAa9XO8vnM27FsOhq3Q4tafq8Wj8xJIysihVe1g5j3YGX9v/c4mIuJx5vP/F9tyczwYiIiIXA3cngFkZWUxYMAA+vbty7x583jkkUeYNWsWI0aMKPSa2bNns3PnTuLi4khNTeW+++5j0qRJvPjii2RkZLB3715OnjyJl5fjl28fH59CyxJxmT9mQ04G1GgB3R6HIn6IIrA6tLrjkocSTp3lle/i+XG7o+t87VA/pg/roIRdRKS8sFzY0q6kXUREXMvtWcCiRYtISUlh8uTJ+Pv7M3HiRMaOHVtk0r527Vpuv/12oqOjAbjlllvYtm0bAHFxcbRq1Yrq1au7JX6Ri5zcAWnHYO00x3anUUUn7IUwDIN3ft7DOz/vJsdmYDWbGHZNXR7p3ZBgP6/iCxAREfcwmbBhxoIdm8a0i4iIi7k9ad+0aROdO3fG398fcHRtj4+PL/Ka5s2bM3v2bG677TbOnTvHvHnzeOwxx5rTa9eu5fDhw1SvXp2cnByGDBnCm2++WWhre1ZWFllZWc7t1NTUS54nUiLHNsMH3c5v+4VBy0u3oBdn+q8JTF66C4Cejavzf/2b0SA8sCyiFBGRMmbDggU7dptmjxcREddy+5JvqampxMTEOLdNJhMWi4WkpKRCrxk5ciTp6elERERQt25dYmJiGDZsGAA7d+6ka9eurFy5ksWLF7N06VKmTJlSaFmTJk0iODjY+YiKiiq7m5Orz75ljme/UIhoCf1eAy+/El++83ga7y7bw8TvtzNx0XYA/nlTE2aN6KiEXUSkHMs1Odo97JqITkREXMztSbvVar2oFdzX15eMjIxCr3nrrbcICQnhwIEDHDx4kNzcXCZMmADA1KlTmTt3Lo0bN6ZTp048++yzzJ8/v9CynnrqKVJSUpyPQ4cOlc2NydXp8DrHc9e/weiV0OrOEl+anpXLPTPW8Prinfz3l30YBtzbJZoHutVzUbAiIlJWbFgcz0raRUTExdzePT4sLIytW7cW2JeWloa3t3eh13z66ae8+OKL1KlTB3C0lvfo0YM33njjonPDw8M5cuRIoWX5+PhoojopO4c3OJ5rdSj1pe8u20NiWhaRwb50b1SdBuGBDL+mbpErKYiISPlgM1nBALsmohMRERdze0t7bGwsq1atcm4nJCSQlZVFWFhYodfY7XZOnjzp3D5+/Dg2m2OprC5duhRoLV+1apVzwjoRl0o5AmlHwWSByDYlusQwDI6lZBJ3MIkZvyYA8OLNLXj1tlaM7FYPq8Xt/yRFROQy2PNa2u02Je0iIuJabm9p7969O6mpqcycOZMRI0YwceJE+vTpg8ViITk5maCgICwWS4FrunXrxquvvorFYiE7O5vXXnuNgQMHAo5J6kaNGsVzzz3Hjh07eOONN3j33XfdfVtyNTqy3vFco5ljDfYSeO6bbXy86oBzu1vDavRuGu6K6ERExIVszjHtStpFRMS13J60W61Wpk+fzpAhQ5gwYQJms5nly5cDEBoaSlxcHG3atClwzcsvv0xqaipPPPEEaWlp9O3bl7feeguAf//734wYMYJevXoRHh7O66+/7pykTsSl8sezl7Br/JbDKcxe7UjY/bwshAV489yA5uoOLyJSAdnzknZDLe0iIuJibk/aAQYOHMjevXvZsGEDnTt3pmrVqoCj6/ClhISE8PHHHxd6bMGCBS6LVaRQ+ePZa8cWe6phGLzw7TYMA25uE8lbd7V1cXAiIuJKdlN+93gt+SYiIq7lkaQdICIigv79+3uqepHLd+QPOLUbjsY5tmsX39K+cPMx1h9Iws/LwpP9mrg4QBGRiuvgwYOcPHmSVq1aFTlJraeppV1ERNxFs16JlEbiLpjeBxY8CLmZ4BMMVRsWeUlmto1J3zvWYB/Tsz41g0u+jruISEW1detWYmNjCQ0NZcKECYX2prvQY489Rrt27bj77ruJiYlhx44dzmOtWrXCZDI5HyNHjnRl+MWya512ERFxEyXtIqWxZioYNgiuA/V6wU3/AnPR/4z++8s+jqaco1aIHw921xrsIlL5ZWVlMWDAANq3b8/69euJj49n1qxZRV6zfPlyFi5cyL59+9i1axc33HADr776KgAZGRns3buXkydPkpSURFJSEu+8844b7qRwdnNeS7td3eNFRMS1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",
      "text/plain": [
       "<Figure size 1200x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "\n",
    "class SimpleNeuralNetwork:\n",
    "    def __init__(self, input_size, hidden_size, output_size,clip_value=1.0):\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.output_size = output_size\n",
    "        self.clip_value = clip_value\n",
    "\n",
    "        # 使用He初始化权重\n",
    "        # self.weights_input_hidden = [[random.gauss(0, math.sqrt(2 / input_size)) for _ in range(hidden_size)] for _ in range(input_size)]\n",
    "        # self.weights_hidden_output = [[random.gauss(0, math.sqrt(2 / hidden_size)) for _ in range(output_size)] for _ in range(hidden_size)]\n",
    "        self.weights_input_hidden = [[random.random() for _ in range(hidden_size)] for _ in range(input_size)]\n",
    "        self.weights_hidden_output = [[random.random() for _ in range(output_size)] for _ in range(hidden_size)]\n",
    "\n",
    "        # 初始化偏置\n",
    "        self.bias_hidden = [random.uniform(-0.5,0.5) for _ in range(hidden_size)]\n",
    "        self.bias_output = [random.uniform(-0.5,0.5) for _ in range(output_size)]\n",
    "\n",
    "    # 激活函数\n",
    "    def sigmoid(self, x):\n",
    "        return 1 / (1 + math.exp(-x))\n",
    "\n",
    "    # 激活函数的导数\n",
    "    def sigmoid_derivative(self, x):\n",
    "        return (1 / (1 + math.exp(-x)))*(1-(1 / (1 + math.exp(-x))))\n",
    "\n",
    "    \n",
    "    \n",
    "    # 前向传播\n",
    "    def feedforward(self, inputs):\n",
    "        # 计算隐藏层输出\n",
    "        hidden_layer_input = [sum(i * w for i, w in zip(inputs, col))+b for col,b in zip(zip(*self.weights_input_hidden),self.bias_hidden)]\n",
    "        hidden_layer_output = [self.sigmoid(x) for x in hidden_layer_input]\n",
    "\n",
    "        # 计算输出层输出\n",
    "        output_layer_input = [sum(h * w for h, w in zip(hidden_layer_output, col))+b for col,b in zip(zip(*self.weights_hidden_output),self.bias_output)]\n",
    "        output_layer_output = [self.sigmoid(x) for x in output_layer_input]\n",
    "\n",
    "        return hidden_layer_output, output_layer_output\n",
    "\n",
    "    #训练模型，并记录每个epoch后的精度与损失\n",
    "    def train(self, training_data, labels, learning_rate, epochs, X_test, y_test):\n",
    "        training_accuracies = []\n",
    "        validation_accuracies = []\n",
    "        training_losses = []\n",
    "        validation_losses = []\n",
    "\n",
    "        for epoch in range(epochs):\n",
    "            for inputs, label in zip(training_data, labels):\n",
    "                # 前向传播\n",
    "                hidden_output, predicted_output = self.feedforward(inputs)\n",
    "\n",
    "                # 计算输出层误差\n",
    "                output_errors = [label - output for output in predicted_output]\n",
    "                output_delta = [error * self.sigmoid_derivative(output) for error, output in zip(output_errors, predicted_output)]\n",
    "\n",
    "                # 计算隐藏层误差\n",
    "                hidden_errors = [sum(w * delta for w, delta in zip(col, output_delta)) for col in self.weights_hidden_output]\n",
    "                hidden_delta = [error * self.sigmoid_derivative(output) for error, output in zip(hidden_errors, hidden_output)]\n",
    "\n",
    "                # 梯度裁剪\n",
    "                output_delta = [max(min(delta, self.clip_value), -self.clip_value) for delta in output_delta]\n",
    "                hidden_delta = [max(min(delta, self.clip_value), -self.clip_value) for delta in hidden_delta]\n",
    "\n",
    "                # 更新隐藏层到输出层的权重和偏置\n",
    "                for i in range(self.hidden_size):\n",
    "                    for j in range(self.output_size):\n",
    "                        self.weights_hidden_output[i][j] += learning_rate * output_delta[j] * hidden_output[i]\n",
    "                    self.bias_output[j] += learning_rate * output_delta[j]\n",
    "\n",
    "                # 更新输入层到隐藏层的权重和偏置\n",
    "                for i in range(self.input_size):\n",
    "                    for j in range(self.hidden_size):\n",
    "                        self.weights_input_hidden[i][j] += learning_rate * hidden_delta[j] * inputs[i]\n",
    "                    self.bias_hidden[j] += learning_rate * hidden_delta[j]\n",
    "\n",
    "            # 每个epoch结束后，计算训练集和验证集的精度和损失\n",
    "            train_loss, train_accuracy = self.evaluate(training_data, labels)\n",
    "            val_loss, val_accuracy = self.evaluate(X_test, y_test)\n",
    "\n",
    "            training_accuracies.append(train_accuracy)\n",
    "            validation_accuracies.append(val_accuracy)\n",
    "            training_losses.append(train_loss)\n",
    "            validation_losses.append(val_loss)\n",
    "\n",
    "            print(f'Epoch {epoch + 1}/{epochs} - Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, '\n",
    "                  f'Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy:.4f}')\n",
    "\n",
    "        return training_losses, validation_losses, training_accuracies, validation_accuracies\n",
    "\n",
    "    # 计算损失函数（均方根误差）\n",
    "    def evaluate(self, data, labels):\n",
    "        total_loss = 0\n",
    "        correct_predictions = 0\n",
    "\n",
    "        for inputs, label in zip(data, labels):\n",
    "            _, predicted_output = self.feedforward(inputs)\n",
    "            loss = sum((label - output) ** 2 for output in predicted_output) / len(predicted_output)\n",
    "            total_loss += loss\n",
    "            if predicted_output.index(max(predicted_output)) == label:\n",
    "                correct_predictions += 1\n",
    "\n",
    "        average_loss = total_loss / len(data)\n",
    "        accuracy = correct_predictions / len(data)\n",
    "\n",
    "        return average_loss, accuracy\n",
    "\n",
    "    # 将输入数据在FNN中进行前向传播，进行分类\n",
    "    def predict(self, inputs):\n",
    "        _, output = self.feedforward(inputs)\n",
    "        # 返回输出层的值（概率）较大的那一类的索引\n",
    "        return output.index(max(output))\n",
    "\n",
    "# 创建一个神经网络实例\n",
    "input_size = len(X_train[0])\n",
    "hidden_size = 35\n",
    "output_size = len(set(y_train))\n",
    "\n",
    "nn = SimpleNeuralNetwork(input_size, hidden_size, output_size)\n",
    "\n",
    "# 训练神经网络\n",
    "learning_rate = 0.002\n",
    "epochs = 200\n",
    "training_losses, validation_losses, training_accuracies, validation_accuracies\\\n",
    "      = nn.train(X_train, y_train, learning_rate, epochs, X_test, y_test)\n",
    "\n",
    "# 绘制精度和损失的变化图\n",
    "plt.figure(figsize=(12, 5))\n",
    "\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.plot(range(1, epochs + 1), training_accuracies, label='Training Accuracy')\n",
    "plt.plot(range(1, epochs + 1), validation_accuracies, label='Test Accuracy')\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.legend()\n",
    "plt.title('Accuracy vs. Epochs')\n",
    "\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.plot(range(1, epochs + 1), training_losses, label='Training Loss')\n",
    "plt.plot(range(1, epochs + 1), validation_losses, label='Test Loss')\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Loss')\n",
    "plt.legend()\n",
    "plt.title('Loss vs. Epochs')\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[268  10]\n",
      " [ 23  52]]\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "predicted=[]\n",
    "for inputs in X_test:\n",
    "    predicted_label = nn.predict(inputs)\n",
    "    predicted.append(predicted_label)\n",
    "matrix=confusion_matrix(y_test,predicted)\n",
    "print(matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 添加第二个隐藏层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({0: 1110, 1: 298}) Counter({0: 278, 1: 75})\n",
      "Epoch 1/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 2/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 3/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 4/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 5/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 6/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 7/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 8/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 9/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 10/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Epoch 11/200 - Train Loss: 0.2116, Train Accuracy: 0.7884, Validation Loss: 0.2125, Validation Accuracy: 0.7875\n",
      "Early stopping...\n"
     ]
    },
    {
     "data": {
      "image/png": "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On78uJo1a6Z169bpkUce0bp16/Tmm29a2q83BknatWuX1Ttk/+///k/Lly9XZmamVqxYodDQ0OvG3UilSpX0yCOPaNWqVbp06ZI2bNhglehL0uLFi/Xtt9/qvvvu0+rVq9W8eXN9/fXXxernZv31fOTm5spkMsnBweGG5+rPcYX9mUtSnTp1VLly5Rvuq3fv3jp48KCGDh2qM2fO6PHHH1e/fv2KeygAgFtAUeYWqfA5ctiwYdq3b58ee+wxHTp0SF27dtWrr75arLEMGDBAq1atkqR8P8iXVh+l4c/nJe/ix83M06dOndLWrVutLqQU9LrkevXq6eDBg5o+fboqVaqkN998U3fffbcyMzOLfSxAaSHRB0rJsWPHdOjQIfXu3VstW7ZUy5Yt1a9fP125ckUbN26UJLVq1Ur//e9/reKGDh2qt99+29J+4sQJq4R6+fLlat++veVXY0dHR128eNGqPa+tKJYvX67z589rw4YNGjFihIKCgnTw4EFLe9OmTeXi4mI1zj/++EPBwcFauXKlZVu/fv2Uk5OjF198USaTSb179y7yGPL0799fq1at0qZNm+Tn56cWLVpY2vbs2aM333xT7du317hx47R161YFBQVp4cKFxe7nZvz66686fPiwZX3Hjh1q2LChHBwcdN9998lkMln+fKVrVxCOHTtmuaJQ2J+5dO3PtCBhYWE6f/68nnvuOX366af64IMPtGzZsnIteAQAKB8+Pj6qV6+e1dxy5coVbdmyxTK3FDZHXrx4US+//LI8PT01atQoLV26VGPHjlVkZGSxxtK3b1/t2bNHR44c0datW61+ZC6tPkrD5s2bLf+9Y8cOmUwmNW7cuEjnslWrVtqzZ49VUj537lw98sgjcnD4X6pU0FwdGRmpTZs2qX///oqIiNDmzZuVlJSk77//vjQPEygWbt0HSknebft5t8BL15Lm6tWra8OGDerTp4/efPNN9e7dWy+++KJCQkK0ZcsW/fe//9XatWslSU888YSmT5+uvn376p133tHFixc1ceJEDRgwwHJL2d13362oqCh17dpVsbGxCgsLU5UqVYo8zurVq+vy5ctasGCB7rjjDi1cuFBffvml5bY3d3d3vfTSS5o+fbo8PT1111136cMPP1SVKlX02GOPWfbj5eWl3r17a9GiRXrhhRfk4uJS7HP20EMP6emnn9b7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zZs3a/DgwTKZTHrhhReK1F98fLzatWsnT09PPfzwwzpx4oQkadOmTWrQoIG++eYb1a9fX97e3vrXv/5VpGM7c+aMdu/erVdffTVfoh8XF6c2bdqoatWqeuCBB7Rv375C2/LG8mcmk0nJycmSpEGDBmnixIn67LPPFBAQoA8//LDQc1ZQf59++qmaNWtm+dz58+dVuXJl7d+/v0jHX1bq1aunH374wWrbDz/8oPr169toRABQAfH9wm6/XxRky5Ytatmypcxms5544gmlp6db2hYvXix/f39VqVJF3bp109mzZy1ts2bNUp06deTu7q7+/fvrjz/+uOmx3EixE31/f381bNjQsjRo0ECNGzfWwIEDy2J8AFA6Ll+UptaxzXL5YpGG6OjoqAcffNBye92WLVvUtWtXSdcem3rssccUEhKio0ePqn379ho9evRNnZJTp06pf//+Gjt2rLZv365Vq1ZZ2grqb9asWTp37pweeOABzZkzR+fOndOsWbMK7e/8+fN66KGH1LVrV+3Zs0d+fn565JFHlJubK+naj8YzZszQmjVr9Pbbb+vVV18t0gT43Xff6Y477lCXLl30+++/a+/evZKu3ZrYvXt39ezZUwcOHFBgYKCefPLJQtuK4ttvv9W//vUv/fOf/1SfPn0KPWcF9ffII4/oyJEjOnDggKRrV9LvuOMO3XnnnUUeT1mYPXu2XnrpJXXv3l3Dhw9X9+7d9Y9//EMffPCBTccFABUK3y/ysZfvFzeSkpKihx9+WCNGjFBsbKzOnz+vQYMGSZKysrIUGhqqadOmad++fXJyctJ7770nSdq/f7/GjBmjL774Qj///LMOHz6sRYsWlXgchSl21f2/Pi9hMpnk6+urRo0aldaYAOC29dBDD+nLL79Udna2YmNjtXjxYktbXFyczGaz9uzZo/T0dEtiWFLr1q2Tv7+/hg4dKkmaOHGievbsWWh/lStXVuXKleXk5CQ3N7ci30K3cuVKubu7a8KECZKuJZI1atTQzp07JV2bqD/88EM1a9ZMTZo00ahRo3Tq1KlCryCvX79eQUFBqlSpklq1aqUNGzborrvu0urVq2U2mzVu3DhJ0oQJE9SmTRtJKrCtKI4cOaJDhw7J09PTavuNzllB/Xl4eKh79+5aunSp3njjDX399dfq379/kcdSVtq3b6/ExER99tlnSklJUadOnRQZGanTp0/bemgAgGLi+0Xxv1/cyGeffaa2bdtaju/DDz9U3bp1lZqaKk9PTzk5OenSpUuqXbu2vvnmG8sPDq6urpKkS5cuyd/fXzt27ChR/0VV7ES/Q4cOVuunT5+Wj49PqQ0IAMqEs5v0xknb9V1EXbt21T/+8Q9t2bJFDRo0sExCDg4OmjVrlhYsWKCGDRvKz89PV69evalh/fbbb1avRf3zD7Zl0V9KSorVG1oqVaokX19fHT9+XD4+PjKbzWrRooUkycXFRZJkFOG2xA0bNujs2bNavny5Ll68KC8vL73yyiv5+jObzZYEuqC2v7p4Mf8Vk9DQ0HxJfkHnrLD+Hn/8cYWHh2vMmDFavXq13n777UKPuzzUrVtXYWFhlvVff/1VgYGBN/13AQDsBt8v8rGX7xcF9dewYUPLuq+vr1xdXXX8+HG1bt1aX3zxhd59912NGjVK7dq1U0REhBo2bCh/f3999NFHev3113X48GF1795dH3zwgWrUqFHisRSk2LfuJyQk6J577tF//vMfSVLnzp3VrFkzHTx4sNQHBwClxmSSXKrYZinGa2AaNmyo2rVra+bMmZbb6qRrz5hFRkYqISFBO3fu1LPPPnvTp8THx0cnT/7vy8nx48eL1Z+Dg0OxJsp69eopKSnJsp6Tk6OTJ09avmx4eHgU+xgSEhL066+/avPmzfrll18UGRmpLVu2KCcnR35+fpbn6qVrv+g3b95cqampBbaZTCbLr++SFBsbm6/fKlWq5NtW0DkrqD9J6tOnjxISErRw4UI1bty4Qt8ldzNfjgDA7vD9Ih97+H5RWH9Hjx61rJ88eVI5OTmqX7++0tLSVLNmTW3dulWnTp1S9erV9fLLL1s+d99992nXrl1KTk7W2bNnNXny5FId258VO9F//vnn1aFDB8vrGLZv367evXvnK5QAACiZrl276vvvv7eaiLOysiRJ6enp+vHHH/XKK6/cdML10EMPaf/+/Vq0aJGOHDmiiRMnFqu/Ro0a6YcfftBvv/2m7777rtBf5Hv16qWsrCxNmjRJx44d04svvqgmTZooMDCwxMewfv16NW7cWPfff78aNGigvn376vLly9q6dat69uyptLQ0TZs2TSdOnNCUKVN09epV1axZs8A2X19f/fbbbzp27JguXrxouRWwMAWds4L6k6SqVauqR48eeu211yrEbfsFKY/3FwMASh/fL4rn8uXLOnHihNVy+fJlPfnkk4qJidH8+fOVlJSkYcOG6dFHH1XNmjV1+vRpdezYUevWrVNaWpok6cqVK5KuFQx86KGH9OOPP1rOQ15bmTCKqWrVqsbJkyettp04ccLw8PAo7q5uaRkZGYYkIyMjw9ZDAXAd2dnZRkJCgpGdnW3roRTbV199ZTg5OVn9+3Lp0iXjiSeeMKpUqWI0b97c+Oc//2k4OTkZqampls8kJSUZN/pn/UZtX331leHv72/UqlXLGDNmjOUzRekvOTnZaNOmjeHs7Gw0atTIuHTpUqH97dmzx2jbtq3h7u5udO/e3UhJSTEMwzA2btxo1K9f3+qzkoykpKQCz9XDDz9sPPfcc1bb2rZta7z22muGYRjGzz//bAQFBRlVq1Y1OnToYCQmJlo+V1Dbq6++avj6+hqtWrUyvv76a6uxhIaGGhMmTMg3lsLOWUH9GYZhfPnll4YkIzk5ucBjLujvdlnPTSdOnDAcHBzKZN8VEXM9gD+7lb9bGAbfL/IU5fvFwoULDUn5ll27dhmGYRibNm0y7r77bsPT09MYMGCAce7cOUvsnDlzjAYNGhiVKlUy7r//fiM+Pt7SNn78eKN27dpG5cqVjc6dOxu//vrrdfsvjbne9P8Ptsjatm2r3r176/XXX7dsmzFjhlasWKGYmJib+c3hlpKZmSlPT09lZGSU+u0gAG7eH3/8oaSkJPn7+6tSpUq2Hg5QoKNHj+q///2vPv74Y/34448Ffragv9s3Oze1atWqwCv2ly5dUmJi4m3zjD5zPYA/47sFyktpzPXFLsY3Z84c9ejRQ59++qn8/f2VnJystLQ0rVu3rsj7iI+P1+DBg3X48GENGTJE7777boFfLAYNGnTdVw8kJSWpZs2aevrpp/Xtt9/K1dVVoaGhevfdd+Xg4KCOHTtq8+bN+eIMw1BqaqpGjRqlH374QdWrV9fkyZP1+OOPF/kYAAAoLX369NGZM2e0ZMkSm44j7zlCAABwayt2ot+qVSsdPHhQq1evVkpKip566in17NmzyL905+TkqHfv3urWrZu++OILvfjii4qKitLgwYNvGDN37ly9//77lvVt27bppZdekp+fn9555x05OzsrMTFRJ0+e1OOPP66mTZvqmWee0apVq6yee/jyyy/15ZdfSpIee+wx+fn5ac+ePdqxY4eefPJJeXt7q0uXLsU9JQAA3JT4+HhbD0HStbcJAACAW1+xE33pWuXCgQMHSrr2er3i3M62du1aZWRkKDw8XG5ubpo6dapGjBhRYKLv5uYmN7f/vT5i1qxZmjhxohwdHbVz504NHz5cvr6+8vX1VZcuXXT48GFJ14ob5cnNzdX777+vBQsW6OjRo9q2bZuWL1+uGjVqKCQkRL1799Y333xDog8AAAAAuKWV++v1du/eraCgIEvi3qJFCyUkJBS5/127dikpKUkDBgyQJDVr1kyRkZFKT0/Xvn37tHr1aqtKknmWLl2qOnXqqG3btjp79qwqV65s9c5CR0dHOTo63rDfnJwcZWZmWi0AKr5iliEBKjz+TgOAbfHvMMpaafwdK/fX62VmZsrf39+ybjKZ5OjoqHPnzhUpPiIiQsOGDZODw7Whh4WFadu2bTKbzWrevLlCQkLUqVOn68aNGDFCknTnnXfKMAx99913kqTU1FStW7fuuj8Q5Jk2bZo8PT0ti5+fX5HGC8A28n64u3Tpko1HApSuixcvSpKcnZ1tPBIAuL3k/bub9+8wUFZKY64v9q37v/zyi5YsWSJPT09JUpUqVTRq1Cg1bdq0aB06OcnV1dVqW6VKlXTx4kWZzeYCY9PS0rRixQrNnj3bsm38+PFq166d5syZo3Pnzumpp55SRESERo0aZfnMvn37dPjwYT3yyCOSrj168OGHH2rgwIFq06aNtm7dqho1aqhbt2437Pv111/XK6+8YlnPzMwk2QcqMCcnJ7m5uenMmTNydna2/DgI3KoMw9DFixd1+vRpeXl5FXgXWkVQ3MK7kjRp0iTNnj1bFy5c0MMPP6x///vfcnd3t7THxMRo8ODBOnDgQJHjvvrqK7366qu6fPmy3nvvPcujhwBQXI6OjvLy8tLp06clXXu8uLB/14DiKM25vtiJ/l133aWoqCir1+t99tlnatasWZHivb298xUdysrKkouLS6Gxy5YtU3BwsNUPAtHR0dqyZYt8fHzk4+OjcePGacKECVaJ/uLFixUSEmJ1op5++mn17dtX8fHx6ty5s+WZ/xtxdXXN9wMFgIrLZDKpdu3aSkpK0rFjx2w9HKDUeHl5qVatWrYeRoFKUng3Ojpa0dHRWrdunby9vdWrVy9Nnz5d77zzjiQpNjZWffv2VeXKlYscFx8fryeffFJz5szR/fffr5CQEN1zzz0KCAgo0+MHYL/y/v3NS/aBslAac/1Nv14vKSlJ586dK/Lr9QIDAzV//nzLelJSknJycuTt7V1o7JIlSyzP5ufJzc21+h8tNTU13/t9lyxZonnz5uXbn7u7u3788Ufdeeed/MIP2CEXFxc1adKE2/dhN5ydnSv8lXypZIV3U1JStGjRIrVu3VqS1L9/f+3atUuSdOHCBYWEhGjkyJFasGBBkeMiIyPVqVMnDRkyRJI0cuRIffrpp5oyZUqpHzOA20PehQQfHx9dvnzZ1sOBHSqtuf6mX683YMAAeXp66osvvtDdd99daHz79u2VmZmphQsXavDgwZo6daq6dOkiR0dHpaeny93d/boHlp2drc2bN+dL2IODgxUWFqaXX35Zv//+u6ZMmaKhQ4da2o8ePapjx46pbdu2+faZlZWld999V4sXL+a2G8BOOTg4qFKlSrYeBnBbKUnh3bCwMKv1AwcOqEmTJpKufemJiYnRoUOH8iX6BcXt3r1bPXr0sLS1bt1ab7/99g3HkJOTo5ycHMs6hXcB3EhhhbwBWyvR6/VSUlJ06tQpbdq0SVu2bNHly5ctv6QX2qGTkyIjIzVw4ECNGTNGDg4O2rRpkyTJbDYrLi5OLVu2zBcXExMjs9mshg0bWm2fN2+ehg8frlGjRunSpUt6/PHHNW7cOEv7xo0b1apVq+t+0X/vvfd0//33q3PnzkU/eAAAUKCCCu8WVo9Hkg4ePKjly5fr559/lnTt7hxfX18dOnSoWHF/HYeHh4dOnjx5w/hp06Zp0qRJhY4PAICKrkiJ/pkzZ7RhwwZt2LBB69ev1++//65WrVopLi5O8+fPV9++fa3eWV+YPn366MiRI4qNjVVQUJCqVasmqeDXCHTu3Fmpqan5ttetW1fffPPNDeOeffZZPfvss9dtmzhxYpHHDAAAiuZmCu/m5ubqmWee0ZAhQ4pc/+dGcX8dR94YboTCuwAAe1GkRD+vEEDHjh01f/58denSRS4uLjKbzerQoUOxkvw/77Nnz57FjgMAABXbzRTenTx5stLS0jRz5sxi9Xm9OG9vb505c6bIY6DwLgDAXhTpfVPr16/XmDFjlJ6erkceeUStWrXSs88+q5ycHCpOAgAAK4GBgdq2bZtlvaiFd1euXKnw8HAtXbrU8nx/Udwo7q/jiIuLk6+vbzGOBACAW1OREv3OnTtr+vTpio2N1W+//abx48fLMAxVq1ZN999/vwICAjR8+PCyHisAALgF/LnwrqR8hXf/+nYcSUpMTNTAgQMVEREhPz8/nT9/vsDb7IsS9/e//11ffPGF9u7dq/Pnz+uDDz5Qt27dSvdgAQCogIqU6P9Z9erVNWDAAH3yySdKSUlRfHy8hg0bpuPHj5fF+AAAwC0mr/DuyJEjVb16da1YsUIzZsyQdK3w7t69e/PFfPzxx7pw4YJCQ0Pl7u4ud3d3NW3atNC+Coq7++679dJLL+m+++6Tr6+vHB0duTABALgtmIyCKuDhhjIzM+Xp6amMjAx5eHjYejgAAFS4uSk1NTVf4V1bSEhI0K+//qoOHToUqU5Anop2PgEAKOrcVKLX6wEAABSmohTebdq0aZHuDgAAwF4U+9Z9AAAAAABQcZHoAwAAAABgR0j0AQAAAACwIyT6AAAAAADYERJ9AAAAAADsCIk+AAAAAAB2hEQfAAAAAAA7QqIPAAAAAIAdIdEHAAAAAMCOkOgDAAAAAGBHSPQBAAAAALAjJPoAAAAAANgREn0AAAAAAOwIiT4AAAAAAHaERB8AAAAAADtCog8AAAAAgB0h0QcAAAAAwI6Q6AMAAAAAYEdI9AEAAAAAsCMk+gAAAAAA2BESfQAAAAAA7AiJPgAAAAAAdoREHwAAAAAAO0KiDwAAAACAHSHRBwAAAADAjpDoAwAAAABgR2yS6MfHxyswMFBms1ljxoyRYRgFfn7QoEEymUz5luTkZGVnZ6tfv37y8PBQjRo1NHr0aOXm5kqSOnbseN04STpz5oy6du2qKlWqqE6dOpo5c2aZHzcAAAAAAGWt3BP9nJwc9e7dW/fee69++uknJSQkKCoqqsCYuXPn6ty5c5ZlzZo1atKkifz8/DRz5kw5OzsrMTFRa9as0dKlSy37W7VqlVXcvHnz1KlTJ0nS2LFj1bJlSx0+fFifffaZpk6dqh9++KGMjx4AAAAAgLLlVN4drl27VhkZGQoPD5ebm5umTp2qESNGaPDgwTeMcXNzk5ubm2V91qxZmjhxohwdHbVz504NHz5cvr6+8vX1VZcuXXT48GFJUtWqVS0xubm5ev/997VgwQJJ0s6dO7VkyRLVrl1btWvX1n333afDhw/rwQcfLKMjBwAAAACg7JX7Ff3du3crKCjIkri3aNFCCQkJRY7ftWuXkpKSNGDAAElSs2bNFBkZqfT0dO3bt0+rV69W165d88UtXbpUderUUdu2bS1xH374oc6fP68ff/xRO3fuVMeOHW/Yb05OjjIzM60WAAAAAAAqmnJP9DMzM+Xv729ZN5lMcnR01Llz54oUHxERoWHDhsnB4drQw8LCtG3bNpnNZjVv3lwhISGW2/P/GjdixAjL+tSpU/XJJ5/I3d1d7dq10/jx43XHHXfcsN9p06bJ09PTsvj5+RX1kAEAAAAAKDflnug7OTnJ1dXValulSpV08eLFQmPT0tK0YsUKq9v8x48fr3bt2unUqVPav3+/duzYoYiICKu4ffv26fDhw3rkkUcs21566SUNGTJEaWlpio2N1bx58/TNN9/csO/XX39dGRkZliUlJaWohwwAwG2nuIV3JWnSpEny9vaWq6ur+vbtq6ysLKv2mJgYBQQEXDf2em2XL1/WmDFjVK9ePdWuXVtvvfWWrly5UvKDAgDgFlHuib63t7fOnDljtS0rK0suLi6Fxi5btkzBwcEym82WbdHR0Xrrrbfk4+OjgIAAjRs3zvIcfp7FixcrJCREjo6OkqT09HStWbNGU6ZMkdls1j333KNRo0bpk08+uWHfrq6u8vDwsFoAAEB+JSm8Gx0drejoaK1bt0779u1TYmKipk+fbmmPjY1V3759lZOTky/2Rm2TJk3S2rVrtW7dOq1Zs0bR0dGaNGlSqRwjAAAVWbkn+oGBgdq2bZtlPSkpSTk5OfL29i40dsmSJQoJCbHalpubq9OnT1vWU1NTdfXq1QLjDMOQYRiFxgEAgOL7c+HdRo0aaerUqfl+hP+rlJQULVq0SK1bt1bjxo3Vv39/xcXFSZIuXLigkJAQjRw5Ml9cQW3//ve/NWnSJDVt2lStWrXSq6++qhUrVpTOQQIAUIGVe6Lfvn17ZWZmauHChZKuPSvfpUsXOTo6Kj09/YbJdnZ2tjZv3pyvYF5wcLDCwsIUHR2tDz74QOPHj1efPn0s7UePHtWxY8csRfgkyWw2q1mzZho+fLi+/PJLTZ8+XR988IFVHAAAKJmSFN4NCwtTmzZtLOsHDhxQkyZNJEnOzs6KiYlRcHBwvriC2s6ePat69epZ1h0dHS13910PhXcBAPbCJs/oR0ZGauTIkapevbpWrFihGTNmSLqWgO/du/e6cTExMTKbzWrYsKHV9nnz5ql27doaNWqU3njjDfXq1Uvjxo2ztG/cuFGtWrVSpUqVrOK+/PJLXbp0SUOHDtWMGTM0fPhwPfvss6V8tAAA3H5utvDuwYMHtXz5cj333HOSJBcXF/n6+l73swW13XPPPZYr+FevXtWnn3563Tfz5KHwLgDAXpiMolTHKQOpqamKjY1VUFCQqlWrZosh3JTMzEx5enoqIyOD5/UBABVCRZmbxo4dq8uXLys8PNyyzc/PT9u3b79hUp4nNzdX7du319133605c+ZYtW3atEmDBg1ScnJyvrjrte3evVu9evXS3/72Nx05ckTHjx/XwYMHrX6E+LOcnByr5/wzMzPl5+dn8/MJAECeos71TuU4Jiu1atVSz549bdU9AAAoI97e3oqPj7faVtTCu5MnT1ZaWppmzpx50+O4++67lZycrP379+v//u//NHjw4Bsm+dK1wrt/fTMQAAC3Ipsl+gAAwD4FBgZq/vz5lvWiFt5duXKlwsPDtX37dsvz/TfL0dFRFy9e1IEDB7Rq1apS2ScAABVduT+jDwAA7FtJCu8mJiZq4MCBioiIkJ+fn86fP6+LFy+Wynjeeustvfrqq6pTp06p7A8AgIqORB8AAJSqkhTe/fjjj3XhwgWFhobK3d1d7u7uatq06U2PZfPmzfrll1/02muv3fS+AAC4VdisGN+trqIUPAIAIE9Fm5sovAsAQOmq8MX4AACAfaPwLgAAtsGt+wAAAAAA2BESfQAAAAAA7AiJPgAAAAAAdoREHwAAAAAAO0KiDwAAAACAHSHRBwAAAADAjpDoAwAAAABgR0j0AQAAAACwIyT6AAAAAADYERJ9AAAAAADsCIk+AAAAAAB2hEQfAAAAAAA7QqIPAAAAAIAdIdEHAAAAAMCOkOgDAAAAAGBHSPQBAAAAALAjJPoAAAAAANgREn0AAAAAAOwIiT4AAAAAAHaERB8AAAAAADtCog8AAAAAgB0h0QcAAAAAwI6Q6AMAAAAAYEdI9AEAAAAAsCMk+gAAAAAA2BESfQAAAAAA7IhNEv34+HgFBgbKbDZrzJgxMgyjwM8PGjRIJpMp35KcnKzs7Gz169dPHh4eqlGjhkaPHq3c3FxJUseOHa8bJ0kNGjTIt71BgwZlfegAAAAAAJSpck/0c3Jy1Lt3b91777366aeflJCQoKioqAJj5s6dq3PnzlmWNWvWqEmTJvLz89PMmTPl7OysxMRErVmzRkuXLrXsb9WqVVZx8+bNU6dOnSRJe/bssWp744039OCDD5bx0QMAAAAAULacyrvDtWvXKiMjQ+Hh4XJzc9PUqVM1YsQIDR48+IYxbm5ucnNzs6zPmjVLEydOlKOjo3bu3Knhw4fL19dXvr6+6tKliw4fPixJqlq1qiUmNzdX77//vhYsWCBJ8vDwsLRlZWVp4cKFiomJKe3DBQAAAACgXJX7Ff3du3crKCjIkri3aNFCCQkJRY7ftWuXkpKSNGDAAElSs2bNFBkZqfT0dO3bt0+rV69W165d88UtXbpUderUUdu2bfO1zZs3Tz169Cjw1v2cnBxlZmZaLQAAAAAAVDTlnuhnZmbK39/fsm4ymeTo6Khz584VKT4iIkLDhg2Tg8O1oYeFhWnbtm0ym81q3ry5QkJCLLfn/zVuxIgR+bbn5uZq7ty51237s2nTpsnT09Oy+Pn5FWm8AAAAAACUp3JP9J2cnOTq6mq1rVKlSrp48WKhsWlpaVqxYoXVbf7jx49Xu3btdOrUKe3fv187duxQRESEVdy+fft0+PBhPfLII/n2uW7dOtWoUUP33HNPgX2//vrrysjIsCwpKSmFjhcAgNtVcQvvStKkSZPk7e0tV1dX9e3bV1lZWVbtMTExCggIuG7s9doMw9CwYcPk7e0tLy8vDRo0SNnZ2SU/KAAAbhHlnuh7e3vrzJkzVtuysrLk4uJSaOyyZcsUHBwss9ls2RYdHa233npLPj4+CggI0Lhx4yzP4edZvHixQkJC5OjomG+fn3/+uR5//PFC+3Z1dZWHh4fVAgAA8itJ4d3o6GhFR0dr3bp12rdvnxITEzV9+nRLe2xsrPr27aucnJx8sTdq+/TTT3XgwAHFxcXpv//9r/bt26dp06aVyjECAFCRlXuiHxgYqG3btlnWk5KSlJOTI29v70JjlyxZopCQEKttubm5On36tGU9NTVVV69eLTROuvZF5JtvvrluGwAAKJk/F95t1KiRpk6dmu9H+L9KSUnRokWL1Lp1azVu3Fj9+/dXXFycJOnChQsKCQnRyJEj88UV1LZz50499thjql+/vu666y49+uijloK9AADYs3JP9Nu3b6/MzEwtXLhQkjR16lR16dJFjo6OSk9Pz5ek58nOztbmzZvVsWNHq+3BwcEKCwtTdHS0PvjgA40fP159+vSxtB89elTHjh27bhG+H3/8UV5eXmrYsGHpHSAAALe5khTeDQsLU5s2bSzrBw4cUJMmTSRJzs7OiomJUXBwcL64gtqaNWumzz77TKdOndKxY8f0xRdfXLdgbx4K7wIA7IVNntGPjIzUyJEjVb16da1YsUIzZsyQJJnNZu3du/e6cTExMTKbzfmS8nnz5ql27doaNWqU3njjDfXq1Uvjxo2ztG/cuFGtWrVSpUqV8u1z48aN1/0BAAAAlNzNFt49ePCgli9frueee06S5OLiIl9f3+t+tqC2IUOG6Pz586pVq5YaNGggf39/hYaG3rBfCu8CAOxFuSf6ktSnTx8dOXJEixYtUmJiopo2bSrpWtGcli1bXjemc+fOSk1Nzbe9bt26+uabb5SWlqbz58/rk08+UeXKlS3tzz77rLZv337dfU6ePFlffPHFzR8QAACwuJnCu7m5uXrmmWc0ZMgQNWvW7KbGMXv2bHl5eenYsWM6fvy4rly5ojFjxtzw8xTeBQDYC5sk+pJUq1Yt9ezZU9WqVbPVEAAAQBm4mcK7kydPVlpammbOnHnT44iOjtaYMWNUr149+fn5adq0aQXWCqDwLgDAXtgs0QcAAPappIV3V65cqfDwcC1dutTyfP/NKErBXgAA7JGTrQcAAADsy58L7w4ePDhf4V13d/d8r7xNTEzUwIEDNXfuXPn5+en8+fNycHC4qYQ/ODhY06dPl6Ojoy5duqQZM2ZYFewFAMBekegDAIBSlVd4d+DAgRozZowcHBy0adMmSdcK78bFxeWryfPxxx/rwoULCg0NtRTMq1+/vpKTk0s8jilTpigzM1OvvfaasrKy1K1bN82ePbvE+wMA4FZhMgzDsPUgbkWZmZny9PRURkYGz/ABACqEijY3paamKjY2VkFBQbdkTZ6Kdj4BACjq3MQVfQAAUCbyCu8CAIDyRTE+AAAAAADsCIk+AAAAAAB2hEQfAAAAAAA7QqIPAAAAAIAdIdEHAAAAAMCOkOgDAAAAAGBHSPQBAAAAALAjJPoAAAAAANgREn0AAAAAAOwIiT4AAAAAAHaERB8AAAAAADtCog8AAAAAgB0h0QcAAAAAwI6Q6AMAAAAAYEdI9AEAAAAAsCMk+gAAAAAA2BESfQAAAAAA7AiJPgAAAAAAdoREHwAAAAAAO0KiDwAAAACAHSHRBwAAAADAjpDoAwAAAABgR0j0AQAAAACwIyT6AAAAAADYERJ9AAAAAADsCIk+AAAAAAB2xCaJfnx8vAIDA2U2mzVmzBgZhlHg5wcNGiSTyZRvSU5OVnZ2tvr16ycPDw/VqFFDo0ePVm5uriSpY8eO1437s9TUVFWrVk27du0qs+MFAAAAAKC8lHuin5OTo969e+vee+/VTz/9pISEBEVFRRUYM3fuXJ07d86yrFmzRk2aNJGfn59mzpwpZ2dnJSYmas2aNVq6dKllf6tWrbKKmzdvnjp16mS17xdffFF///vfFRgYWEZHDAAAAABA+XEq7w7Xrl2rjIwMhYeHy83NTVOnTtWIESM0ePDgG8a4ubnJzc3Nsj5r1ixNnDhRjo6O2rlzp4YPHy5fX1/5+vqqS5cuOnz4sCSpatWqlpjc3Fy9//77WrBggWXb6tWr9d133+ngwYNlcKQAAAAAAJS/cr+iv3v3bgUFBVkS9xYtWighIaHI8bt27VJSUpIGDBggSWrWrJkiIyOVnp6uffv2afXq1eratWu+uKVLl6pOnTpq27atJCk7O1sjRoxQ9+7dtWrVKh06dKjAfnNycpSZmWm1AAAAAABQ0ZR7op+ZmSl/f3/LuslkkqOjo86dO1ek+IiICA0bNkwODteGHhYWpm3btslsNqt58+YKCQnJd3t+XtyIESMs67Nnz9aJEyfk4eGhPXv2qG3btlq8ePEN+502bZo8PT0ti5+fX1EPGQAAAACAclPuib6Tk5NcXV2ttlWqVEkXL14sNDYtLU0rVqywus1//PjxateunU6dOqX9+/drx44dioiIsIrbt2+fDh8+rEceecSy7eOPP9Yrr7yiefPmKTw8XO+//75effXVG/b9+uuvKyMjw7KkpKQU9ZABALjtFLfwriRNmjRJ3t7ecnV1Vd++fZWVlWXVHhMTo4CAgOvGXq+toGK+AADYs3JP9L29vXXmzBmrbVlZWXJxcSk0dtmyZQoODpbZbLZsi46O1ltvvSUfHx8FBARo3LhxVs/hS9LixYsVEhIiR0dHy7YTJ06oV69elvV77rlHv/322w1/cHB1dZWHh4fVAgAA8itJ4d3o6GhFR0dr3bp12rdvnxITEzV9+nRLe2xsrPr27aucnJx8sTdqK6iYLwAA9qzcE/3AwEBt27bNsp6UlKScnBx5e3sXGrtkyRKFhIRYbcvNzdXp06ct66mpqbp69WqhcXXr1lV2drZl/dixYzKbzVZF/wAAQPH9ufBuo0aNNHXq1Hw/wv9VSkqKFi1apNatW6tx48bq37+/4uLiJEkXLlxQSEiIRo4cmS+uoDY3Nzd5eXlZlj8X8wUAwJ6Ve6Lfvn17ZWZmauHChZKkqVOnqkuXLnJ0dFR6enq+JD1Pdna2Nm/erI4dO1ptDw4OVlhYmKKjo/XBBx9o/Pjx6tOnj6X96NGjOnbsmKUIX56BAwdq/Pjx2rdvn/bs2aM33nhDAwcOLN2DBQDgNlSSwrthYWFq06aNZf3AgQNq0qSJJMnZ2VkxMTEKDg7OF1dQ25/9tZjv9VB4FwBgL2zyjH5kZKRGjhyp6tWra8WKFZoxY4YkyWw2a+/evdeNi4mJkdlsVsOGDa22z5s3T7Vr19aoUaP0xhtvqFevXho3bpylfePGjWrVqpUqVapkFTdx4kS1b99eXbp00QMPPKAmTZro3XffLeWjBQDg9nOzhXcPHjyo5cuX67nnnpMkubi4yNfX97qfLajtz/5azPd6KLwLALAXJqMo1XHKQGpqqmJjYxUUFKRq1arZYgg3JTMzU56ensrIyOB5fQBAhVBR5qaxY8fq8uXLCg8Pt2zz8/PT9u3bC03Kc3Nz1b59e919992aM2eOVdumTZs0aNCg6xbTK6gtLS1N/v7+Sk5Otqrz81c5OTlWz/lnZmbKz8/P5ucTAIA8RZ3rncpxTFZq1aqlnj172qp7AABQRry9vRUfH2+1raiFdydPnqy0tDTNnDmz1MZzvWK+1+Pq6prvzUAAANyKyv3WfQAAYN9KWnh35cqVCg8P19KlS0u1OO71ivICAGDPSPQBAECpKknh3cTERA0cOFARERHy8/PT+fPnb/jK2+K4UTFfAADsGYk+AAAoVSUpvPvxxx/rwoULCg0Nlbu7u9zd3dW0adObHsuNivkCAGDPbFaM71ZXUQoeAQCQp6LNTRTeBQCgdFX4YnwAAMC+UXgXAADb4NZ9AAAAAADsCIk+AAAAAAB2hEQfAAAAAAA7QqIPAAAAAIAdIdEHAAAAAMCOkOgDAAAAAGBHSPQBAAAAALAjJPoAAAAAANgREn0AAAAAAOwIiT4AAAAAAHaERB8AAAAAADtCog8AAAAAgB1xsvUAbnuGIV2+aOtRAABsydlNMplsPQqUEcMwlH35qq2HAQCwscrOjjKV03xPom9rly9KU+vYehQAAFt646TkUsXWo0AZyb58VU3f+tbWwwAA2FjC293k5lI+KTi37gMAAAAAYEe4om9rzm7XruQAAG5fzm62HgHKUGVnRyW83c3WwwAA2FhlZ8dy64tE39ZMJm7XBADAjplMpnK7VRMAAIlb9wEAAAAAsCsk+gAAAAAA2BESfQAAAAAA7AiJPgAAAAAAdoREHwAAAAAAO0KiDwAAAACAHSHRBwAAAADAjpDoAwAAAABgR0j0AQAAAACwIzZJ9OPj4xUYGCiz2awxY8bIMIwCPz9o0CCZTKZ8S3JysrKzs9WvXz95eHioRo0aGj16tHJzcyVJHTt2vG6cJP3+++/5tn/22WdlfuwAAAAAAJSlck/0c3Jy1Lt3b91777366aeflJCQoKioqAJj5s6dq3PnzlmWNWvWqEmTJvLz89PMmTPl7OysxMRErVmzRkuXLrXsb9WqVVZx8+bNU6dOnSRJsbGxCg4Otmrv379/GR89AAAAAABly6m8O1y7dq0yMjIUHh4uNzc3TZ06VSNGjNDgwYNvGOPm5iY3NzfL+qxZszRx4kQ5Ojpq586dGj58uHx9feXr66suXbro8OHDkqSqVataYnJzc/X+++9rwYIFkqRdu3bpgQcekJeXV5HGnZOTo5ycHMt6ZmZmcQ4bAAAAAIByUe5X9Hfv3q2goCBL4t6iRQslJCQUOX7Xrl1KSkrSgAEDJEnNmjVTZGSk0tPTtW/fPq1evVpdu3bNF7d06VLVqVNHbdu2lSTt3LlTy5YtU9WqVeXn56eIiIgC+502bZo8PT0ti5+fX5HHDAAAAABAeSn3RD8zM1P+/v6WdZPJJEdHR507d65I8RERERo2bJgcHK4NPSwsTNu2bZPZbFbz5s0VEhJiuT3/r3EjRoywrB8+fFiDBg1SQkKCwsPD9dprr2n79u037Pf1119XRkaGZUlJSSnqIQMAAAAAUG7K/dZ9Jycnubq6Wm2rVKmSLl68KLPZXGBsWlqaVqxYodmzZ1u2jR8/Xu3atdOcOXN07tw5PfXUU4qIiNCoUaMsn9m3b58OHz6sRx55xGpbnnr16mnt2rX66quvFBQUdN2+XV1drcadV0CQW/gBABVF3pxUWJFbFA1zPQCgoinqXF/uib63t7fi4+OttmVlZcnFxaXQ2GXLlik4ONjqB4Ho6Ght2bJFPj4+8vHx0bhx4zRhwgSrRH/x4sUKCQmRo6PjDfft4+OjY8eOFfk4srKyJIlb+AEAFU5WVpY8PT1tPYxbHnM9AKCiKmyuL/dEPzAwUPPnz7esJyUlKScnR97e3oXGLlmyxPJsfp7c3FydPn3asp6amqqrV6/mi5s3b55l/dixY3riiSe0detWy+v2tm3bpjZt2hT5OOrUqaOUlBS5u7tb9mGPMjMz5efnp5SUFHl4eNh6OBUe56v4OGfFxzkrvtvlnBmGoaysLNWpU8fWQ7ELzPW4Ec5Z8XHOiofzVXy3yzkr6lxf7ol++/btlZmZqYULF2rw4MGaOnWqunTpIkdHR6Wnp8vd3f26V96zs7O1efNmq4RdkoKDgxUWFqaXX35Zv//+u6ZMmaKhQ4da2o8ePapjx45ZivBJ127VP336tN544w099thjWrp0qbZv367IyMgiH4eDg4Pq1q1bgjNwa/Lw8LDr/2FKG+er+Dhnxcc5K77b4ZxxJb/0MNejMJyz4uOcFQ/nq/huh3NWlLm+3IvxOTk5KTIyUiNHjlT16tW1YsUKzZgxQ5JkNpu1d+/e68bFxMTIbDarYcOGVtvnzZun2rVra9SoUXrjjTfUq1cvjRs3ztK+ceNGtWrVSpUqVbJsM5lMWrp0qTZs2KC2bdtq3bp1Wr9+vZo0aVIGRwwAAAAAQPkxGTaq2JOamqrY2FgFBQWpWrVqthgCiiAzM1Oenp7KyMiw+1/GSgPnq/g4Z8XHOSs+zhlwY/z/UXycs+LjnBUP56v4OGfWyv3W/Ty1atVSz549bdU9isjV1VUTJkzI96YEXB/nq/g4Z8XHOSs+zhlwY/z/UXycs+LjnBUP56v4OGfWbHZFHwAAAAAAlL5yf0YfAAAAAACUHRJ9AAAAAADsCIk+AAAAAAB2hEQf17VixQo1bNhQTk5OatmypRITE209pFtK9+7dFRUVZeth3DLGjh2r3r1723oYt4TIyEj5+fnJzc1NHTt21NGjR209JAC3MOb7kmOuLz7m+6JhrkdpINFHPkeOHNHgwYM1ffp0/frrr7rjjjs0ZMgQWw/rlhEdHa1vv/3W1sO4ZezZs0dz587V7NmzbT2UCu/IkSN6++23tWLFCu3fv1+NGjXSoEGDbD2sCuns2bPy9/dXcnKyZVt8fLwCAwNlNps1ZswYUYsWtzvm+5Jjri8+5vuiYa4vHub7GyPRRz6JiYmaPn26Hn/8cdWsWVPDhg1TXFycrYd1S0hLS9Orr76qgIAAWw/llpCbm6vnnntO//jHP9SwYUNbD6fCi4uLU1BQkO655x7Vq1dPzzzzjA4fPmzrYVU4Z8+eVa9evawm/ZycHPXu3Vv33nuvfvrpJyUkJHAlDrc95vuSYa4vPub7omOuLzrm+4KR6COfXr166bnnnrOsHzhwQE2aNLHhiG4dr776qvr27augoCBbD+WWMG/ePO3du1cNGjTQN998o0uXLtl6SBVa06ZN9cMPP+iXX35RRkaG5s6dq65du9p6WBXOgAED9MQTT1htW7t2rTIyMhQeHq5GjRpp6tSpWrBggY1GCFQMzPclw1xffMz3RcdcX3TM9wUj0UeBLl26pPfee08vvPCCrYdS4W3cuFHff/+93n33XVsP5ZZw/vx5TZgwQQ0bNtSxY8c0a9YstWvXTtnZ2bYeWoXVtGlTPfbYY2rVqpW8vLy0bds2/fOf/7T1sCqc+fPn68UXX7Tatnv3bgUFBcnNzU2S1KJFCyUkJNhieECFxHxfNMz1xcd8XzzM9UXHfF8wEn0UaMKECapSpQrP7BXijz/+0PPPP68PP/xQ7u7uth7OLWHZsmW6cOGCNm7cqEmTJmnDhg3KysrSp59+auuhVVg7d+7UypUrtX37dqWnp2vgwIF6+OGHb9tnz27E398/37bMzEyr7SaTSY6Ojjp37lx5Dg2osJjvC8dcXzLM98XDXF90zPcFI9HHDf3www+aM2eOPv/8czk7O9t6OBXa5MmTFRgYqJ49e9p6KLeMEydOKCgoSNWrV5ckOTk5qUWLFjyHVoDFixdrwIABuv/+++Xp6akpU6boyJEj2r17t62HVuE5OTnJ1dXValulSpV08eJFG40IqDiY74uGub5kmO+Lh7n+5jDf/4+TrQeAiikpKUkDBw7UnDlz1LRpU1sPp8L7/PPPdebMGXl5eUmSLl68qCVLlmjnzp2aO3eubQdXQdWtWzffbXvHjh1T27ZtbTSiii83N1dnz561rGdlZenixYu6evWqDUd1a/D29lZ8fLzVtqysLLm4uNhoREDFwHxfdMz1JcN8XzzM9TeH+f5/SPSRT3Z2tnr16qVHHnlEffv21fnz5yVJVapUkclksvHoKqb//ve/unLlimV99OjRCgoK4nUoBejZs6dGjRqlefPmqVevXlq2bJl2796t//znP7YeWoUVHBys0NBQ3XPPPapZs6YiIyNVq1YttWjRwtZDq/ACAwM1f/58y3pSUpJycnLk7e1tw1EBtsV8XzzM9SXDfF88zPU3h/n+f0j0kc/69euVkJCghISEfP+jNGjQwHYDq8Dq1q1rtV61alVVr17dcpsa8qtWrZrWrFmj0aNH65VXXlHt2rW1ZMkS+fn52XpoFdbf//53JSYm6v3339dvv/2m5s2ba/ny5dxqWwTt27dXZmamFi5cqMGDB2vq1Knq0qWLHB0dbT00wGaY74uHub5kmO+Lh7n+5jDf/4/JoLIDAMAOmUwmq4Tlm2++0cCBA1W5cmU5ODho06ZN3KoMAMAtjvn++kj0AQC3jdTUVMXGxiooKEjVqlWz9XAAAEAZYL4n0QcAAAAAwK7wej0AAAAAAOwIiT4AAAAAAHaERB8AAAAAADtCog8AAAAAgB0h0QcAAAAAwI6Q6AMotk2bNslkMlktVatWLZO+oqKi1LFjxzLZNwAAuD7meuDW5mTrAQC4NXl4eOjYsWOWdZPJZMPRAACA0sZcD9y6SPQBlIjJZJKXl5ethwEAAMoIcz1w6+LWfQClZuLEierRo4c6dOggT09PDRgwQJmZmZb2LVu2qGXLljKbzXriiSeUnp5uafv+++/VokULubu7q0ePHjpx4oTVvufPn6+aNWuqZs2aWrZsmWX74sWL5e/vrypVqqhbt246e/ZsmR8nAAC3K+Z64NZAog+gRDIyMuTl5WVZhg8fLklat26dnn32Wf30009KTk7W+PHjJUkpKSl6+OGHNWLECMXGxur8+fMaNGiQJCkpKUm9e/fWyy+/rISEBHl4eGjkyJGWvuLj47Vs2TL9+OOPGjx4sF5++WVJUlZWlkJDQzVt2jTt27dPTk5Oeu+998r1PAAAYK+Y64Fbl8kwDMPWgwBwa9m0aZP69OmjPXv2WLZVrVpV//rXv/Tdd99p69atkqTly5frH//4h5KTkzVt2jRt3LhR69evlyT9+uuvqlu3rn777Td98skn2rx5s7799ltJ0okTJ/TLL7+oV69eioqK0rBhw3Ts2DH5+Pjo4MGDCggIkGEYys7OVrVq1TRv3jz1799fTk5Oys3NlbOzc/mfFAAA7AhzPXBr44o+gBJxcHBQgwYNLEv16tUlSX5+fpbP+Pr66tSpU5Ku/crfsGFDqzZXV1cdP348X1vdunXVq1cvy/rf/vY3+fj4SJJcXFws2ytXrqwvvvhCH3/8sXx8fNSnTx+lpKSUzQEDAHCbYa4Hbl0k+gBKVXJysuW/U1JSVKtWLUlSvXr1dPToUUvbyZMnlZOTo/r168vPz88q7uDBg2rVqpVyc3MlXav6ez1paWmqWbOmtm7dqlOnTql69eqWW/0AAEDZYK4HKj4SfQAlYhiG0tPTrZarV69q+/btWrRokQ4dOqQZM2bo73//uyTpySefVExMjObPn6+kpCQNGzZMjz76qGrWrKmBAwdqy5YtioqKUkpKiqZMmSIfHx85OBT8T9Tp06fVsWNHrVu3TmlpaZKkK1eulPmxAwBwO2CuB25dJPoASiQzM1Nms9lq2bVrl3r37q3IyEjdc889atSokSZMmCDp2m1+q1ev1pw5c9SqVSu5ublp4cKFkiR/f3+tWLFC4eHhatasmdLT0y1tBbnzzjv13nvvadiwYWrUqJEOHDigmTNnlulxAwBwu2CuB25dFOMDUGomTpyo5ORkRUVF2XooAACgDDDXA7cGrugDAAAAAGBHuKIPAAAAAIAd4Yo+AAAAAAB2hEQfAAAAAAA7QqIPAAAAAIAdIdEHAAAAAMCOkOgDAAAAAGBHSPQBAAAAALAjJPoAAAAAANgREn0AAAAAAOzI/wOfDhN+zFh9vwAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1200x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import csv\n",
    "import pandas as pd\n",
    "import random\n",
    "import math\n",
    "from sklearn.model_selection import train_test_split\n",
    "from collections import Counter\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def read_csv(filename, test_size=0.2):\n",
    "    dataset = pd.read_csv(filename)\n",
    "    data = dataset.iloc[:, 1:-1].values\n",
    "    labels = dataset['Forest'].values\n",
    "    X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=test_size, random_state=0, stratify=dataset['Forest'])\n",
    "    return X_train, y_train, X_test, y_test\n",
    "\n",
    "X_train, y_train, X_test, y_test = read_csv(\"D:\\Lenovo\\Desktop\\云南大学\\空间数据挖掘\\实验数据\\data6.csv\")\n",
    "print(Counter(y_train), Counter(y_test))\n",
    "\n",
    "class SimpleNeuralNetwork:\n",
    "    def __init__(self, input_size, hidden_size1, hidden_size2, output_size, learning_rate=0.01, l2_lambda=0.01, clip_value=1.0):\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size1 = hidden_size1\n",
    "        self.hidden_size2 = hidden_size2\n",
    "        self.output_size = output_size\n",
    "        self.learning_rate = learning_rate\n",
    "        self.l2_lambda = l2_lambda\n",
    "        self.clip_value = clip_value\n",
    "        random.seed(1)\n",
    "        # 使用He初始化权重\n",
    "        self.weights_input_hidden1 = [[random.random() for _ in range(hidden_size1)] for _ in range(input_size)]\n",
    "        self.weights_hidden1_hidden2 = [[random.random() for _ in range(hidden_size2)] for _ in range(hidden_size1)]\n",
    "        self.weights_hidden2_output = [[random.random() for _ in range(output_size)] for _ in range(hidden_size2)]\n",
    "\n",
    "        # 初始化偏置\n",
    "        self.bias_hidden1 = [0 for _ in range(hidden_size1)]\n",
    "        self.bias_hidden2 = [0 for _ in range(hidden_size2)]\n",
    "        self.bias_output = [0 for _ in range(output_size)]\n",
    "\n",
    "    def relu(self, x):\n",
    "        return max(0, x)\n",
    "\n",
    "    def relu_derivative(self, x):\n",
    "        return 1 if x > 0 else 0\n",
    "\n",
    "    def feedforward(self, inputs):\n",
    "        # 计算第一个隐藏层输出\n",
    "        hidden_layer1_input = [sum(i * w for i, w in zip(inputs, col)) + b for col, b in zip(zip(*self.weights_input_hidden1), self.bias_hidden1)]\n",
    "        hidden_layer1_output = [self.relu(x) for x in hidden_layer1_input]\n",
    "\n",
    "        # 计算第二个隐藏层输出\n",
    "        hidden_layer2_input = [sum(h * w for h, w in zip(hidden_layer1_output, col)) + b for col, b in zip(zip(*self.weights_hidden1_hidden2), self.bias_hidden2)]\n",
    "        hidden_layer2_output = [self.relu(x) for x in hidden_layer2_input]\n",
    "\n",
    "        # 计算输出层输出\n",
    "        output_layer_input = [sum(h * w for h, w in zip(hidden_layer2_output, col)) + b for col, b in zip(zip(*self.weights_hidden2_output), self.bias_output)]\n",
    "        output_layer_output = [self.relu(x) for x in output_layer_input]\n",
    "\n",
    "        return hidden_layer1_output, hidden_layer2_output, output_layer_output\n",
    "\n",
    "    def train(self, training_data, labels, epochs, X_test, y_test, patience=10):\n",
    "        training_accuracies = []\n",
    "        validation_accuracies = []\n",
    "        training_losses = []\n",
    "        validation_losses = []\n",
    "        best_val_loss = float('inf')\n",
    "        patience_counter = 0\n",
    "\n",
    "        for epoch in range(epochs):\n",
    "            for inputs, label in zip(training_data, labels):\n",
    "                # 前向传播\n",
    "                hidden_output1, hidden_output2, predicted_output = self.feedforward(inputs)\n",
    "\n",
    "                # 计算输出层误差\n",
    "                output_errors = [label - output for output in predicted_output]\n",
    "                output_delta = [error * self.relu_derivative(output) for error, output in zip(output_errors, predicted_output)]\n",
    "\n",
    "                # 计算第二个隐藏层误差\n",
    "                hidden_errors2 = [sum(w * delta for w, delta in zip(col, output_delta)) for col in self.weights_hidden2_output]\n",
    "                hidden_delta2 = [error * self.relu_derivative(output) for error, output in zip(hidden_errors2, hidden_output2)]\n",
    "\n",
    "                # 计算第一个隐藏层误差\n",
    "                hidden_errors1 = [sum(w * delta for w, delta in zip(col, hidden_delta2)) for col in self.weights_hidden1_hidden2]\n",
    "                hidden_delta1 = [error * self.relu_derivative(output) for error, output in zip(hidden_errors1, hidden_output1)]\n",
    "\n",
    "                # 梯度裁剪\n",
    "                output_delta = [max(min(delta, self.clip_value), -self.clip_value) for delta in output_delta]\n",
    "                hidden_delta2 = [max(min(delta, self.clip_value), -self.clip_value) for delta in hidden_delta2]\n",
    "                hidden_delta1 = [max(min(delta, self.clip_value), -self.clip_value) for delta in hidden_delta1]\n",
    "\n",
    "                # 更新第二个隐藏层到输出层的权重和偏置\n",
    "                for i in range(self.hidden_size2):\n",
    "                    for j in range(self.output_size):\n",
    "                        self.weights_hidden2_output[i][j] += self.learning_rate * output_delta[j] * hidden_output2[i]\n",
    "                    self.bias_output[j] += self.learning_rate * output_delta[j]\n",
    "\n",
    "                # 更新第一个隐藏层到第二个隐藏层的权重和偏置\n",
    "                for i in range(self.hidden_size1):\n",
    "                    for j in range(self.hidden_size2):\n",
    "                        self.weights_hidden1_hidden2[i][j] += self.learning_rate * hidden_delta2[j] * hidden_output1[i]\n",
    "                    self.bias_hidden2[j] += self.learning_rate * hidden_delta2[j]\n",
    "\n",
    "                # 更新输入层到第一个隐藏层的权重和偏置\n",
    "                for i in range(self.input_size):\n",
    "                    for j in range(self.hidden_size1):\n",
    "                        self.weights_input_hidden1[i][j] += self.learning_rate * hidden_delta1[j] * inputs[i]\n",
    "                    self.bias_hidden1[j] += self.learning_rate * hidden_delta1[j]\n",
    "\n",
    "            # 每个epoch结束后，计算训练集和验证集的精度和损失\n",
    "            train_loss, train_accuracy = self.evaluate(training_data, labels)\n",
    "            val_loss, val_accuracy = self.evaluate(X_test, y_test)\n",
    "\n",
    "            training_accuracies.append(train_accuracy)\n",
    "            validation_accuracies.append(val_accuracy)\n",
    "            training_losses.append(train_loss)\n",
    "            validation_losses.append(val_loss)\n",
    "\n",
    "            print(f'Epoch {epoch + 1}/{epochs} - Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, '\n",
    "                  f'Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy:.4f}')\n",
    "\n",
    "            # Early stopping\n",
    "            if val_loss < best_val_loss:\n",
    "                best_val_loss = val_loss\n",
    "                patience_counter = 0\n",
    "            else:\n",
    "                patience_counter += 1\n",
    "                if patience_counter >= patience:\n",
    "                    print(\"Early stopping...\")\n",
    "                    break\n",
    "\n",
    "        return training_losses, validation_losses, training_accuracies, validation_accuracies\n",
    "\n",
    "    def evaluate(self, data, labels):\n",
    "        total_loss = 0\n",
    "        correct_predictions = 0\n",
    "\n",
    "        for inputs, label in zip(data, labels):\n",
    "            _, _, predicted_output = self.feedforward(inputs)\n",
    "            loss = sum((label - output) ** 2 for output in predicted_output) / len(predicted_output)\n",
    "            total_loss += loss\n",
    "            if predicted_output.index(max(predicted_output)) == label:\n",
    "                correct_predictions += 1\n",
    "\n",
    "        average_loss = total_loss / len(data)\n",
    "        accuracy = correct_predictions / len(data)\n",
    "\n",
    "        return average_loss, accuracy\n",
    "\n",
    "    def predict(self, inputs):\n",
    "        _, _, output = self.feedforward(inputs)\n",
    "        return output.index(max(output))\n",
    "\n",
    "# 创建一个神经网络实例\n",
    "input_size = len(X_train[0])\n",
    "hidden_size1 = 35\n",
    "hidden_size2 = 35\n",
    "output_size = len(set(y_train))\n",
    "\n",
    "nn = SimpleNeuralNetwork(input_size, hidden_size1, hidden_size2, output_size, learning_rate=0.002)\n",
    "\n",
    "# 训练神经网络\n",
    "epochs = 200\n",
    "patience = 10  # 早停的耐心参数\n",
    "training_losses, validation_losses, training_accuracies, validation_accuracies = nn.train(X_train, y_train, epochs, X_test, y_test, patience)\n",
    "\n",
    "# 绘制精度和损失的变化图\n",
    "plt.figure(figsize=(12, 5))\n",
    "\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.plot(range(1, len(training_accuracies) + 1), training_accuracies, label='Training Accuracy')\n",
    "plt.plot(range(1, len(validation_accuracies) + 1), validation_accuracies, label='Validation Accuracy')\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.legend()\n",
    "plt.title('Accuracy vs. Epochs')\n",
    "\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.plot(range(1, len(training_losses) + 1), training_losses, label='Training Loss')\n",
    "plt.plot(range(1, len(validation_losses) + 1), validation_losses, label='Validation Loss')\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Loss')\n",
    "plt.legend()\n",
    "plt.title('Loss vs. Epochs')\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 自动调整epoch寻找最优模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1, Accuracy: 50.00%\n",
      "Epoch: 2, Accuracy: 50.00%\n",
      "Epoch: 3, Accuracy: 50.00%\n",
      "Epoch: 4, Accuracy: 50.00%\n",
      "Epoch: 5, Accuracy: 50.00%\n",
      "Epoch: 6, Accuracy: 50.00%\n",
      "Epoch: 7, Accuracy: 50.00%\n",
      "Epoch: 8, Accuracy: 50.00%\n",
      "Epoch: 9, Accuracy: 50.00%\n",
      "Epoch: 10, Accuracy: 50.00%\n",
      "Epoch: 11, Accuracy: 50.00%\n",
      "Epoch: 12, Accuracy: 50.00%\n",
      "Epoch: 13, Accuracy: 50.00%\n",
      "Epoch: 14, Accuracy: 44.63%\n",
      "Epoch: 15, Accuracy: 50.00%\n",
      "Epoch: 16, Accuracy: 50.00%\n",
      "Epoch: 17, Accuracy: 50.00%\n",
      "Epoch: 18, Accuracy: 50.00%\n",
      "Epoch: 19, Accuracy: 50.00%\n",
      "Epoch: 20, Accuracy: 50.00%\n",
      "Epoch: 21, Accuracy: 50.00%\n",
      "Epoch: 22, Accuracy: 50.00%\n",
      "Epoch: 23, Accuracy: 50.00%\n",
      "Epoch: 24, Accuracy: 50.00%\n",
      "Epoch: 25, Accuracy: 50.00%\n",
      "Epoch: 26, Accuracy: 50.00%\n",
      "Epoch: 27, Accuracy: 58.05%\n",
      "Epoch: 28, Accuracy: 50.00%\n",
      "Epoch: 29, Accuracy: 50.00%\n",
      "Epoch: 30, Accuracy: 50.00%\n",
      "Epoch: 31, Accuracy: 50.00%\n",
      "Epoch: 32, Accuracy: 50.00%\n",
      "Epoch: 33, Accuracy: 50.00%\n",
      "Epoch: 34, Accuracy: 50.00%\n",
      "Epoch: 35, Accuracy: 50.00%\n",
      "Epoch: 36, Accuracy: 50.00%\n",
      "Epoch: 37, Accuracy: 41.61%\n",
      "Epoch: 38, Accuracy: 50.00%\n",
      "Epoch: 39, Accuracy: 50.00%\n",
      "Epoch: 40, Accuracy: 72.15%\n",
      "Epoch: 41, Accuracy: 50.00%\n",
      "Epoch: 42, Accuracy: 50.00%\n",
      "Epoch: 43, Accuracy: 50.00%\n",
      "Epoch: 44, Accuracy: 26.85%\n",
      "Epoch: 45, Accuracy: 50.00%\n",
      "Epoch: 46, Accuracy: 50.00%\n",
      "Epoch: 47, Accuracy: 50.00%\n",
      "Epoch: 48, Accuracy: 50.00%\n",
      "Epoch: 49, Accuracy: 50.00%\n",
      "Epoch: 50, Accuracy: 50.00%\n",
      "Epoch: 51, Accuracy: 49.66%\n",
      "Epoch: 52, Accuracy: 50.00%\n",
      "Epoch: 53, Accuracy: 77.35%\n",
      "Epoch: 54, Accuracy: 50.00%\n",
      "Epoch: 55, Accuracy: 50.00%\n",
      "Epoch: 56, Accuracy: 50.00%\n",
      "Epoch: 57, Accuracy: 50.00%\n",
      "Epoch: 58, Accuracy: 50.00%\n",
      "Epoch: 59, Accuracy: 50.00%\n",
      "Epoch: 60, Accuracy: 72.15%\n",
      "Epoch: 61, Accuracy: 44.46%\n",
      "Epoch: 62, Accuracy: 50.00%\n",
      "Epoch: 63, Accuracy: 30.87%\n",
      "Epoch: 64, Accuracy: 50.00%\n",
      "Epoch: 65, Accuracy: 50.00%\n",
      "Epoch: 66, Accuracy: 60.23%\n",
      "Epoch: 67, Accuracy: 49.50%\n",
      "Epoch: 68, Accuracy: 50.00%\n",
      "Epoch: 69, Accuracy: 50.00%\n",
      "Epoch: 70, Accuracy: 50.00%\n",
      "Epoch: 71, Accuracy: 50.00%\n",
      "Epoch: 72, Accuracy: 50.00%\n",
      "Epoch: 73, Accuracy: 50.00%\n",
      "Epoch: 74, Accuracy: 50.00%\n",
      "Epoch: 75, Accuracy: 50.00%\n",
      "Epoch: 76, Accuracy: 50.00%\n",
      "Epoch: 77, Accuracy: 50.00%\n",
      "Epoch: 78, Accuracy: 50.00%\n",
      "Epoch: 79, Accuracy: 50.00%\n",
      "Epoch: 80, Accuracy: 40.77%\n",
      "Epoch: 81, Accuracy: 50.00%\n",
      "Epoch: 82, Accuracy: 50.00%\n",
      "Epoch: 83, Accuracy: 50.00%\n",
      "Epoch: 84, Accuracy: 50.00%\n",
      "Epoch: 85, Accuracy: 50.00%\n",
      "Epoch: 86, Accuracy: 50.00%\n",
      "Epoch: 87, Accuracy: 77.68%\n",
      "Epoch: 88, Accuracy: 30.87%\n",
      "Epoch: 89, Accuracy: 68.96%\n",
      "Epoch: 90, Accuracy: 50.00%\n",
      "Epoch: 91, Accuracy: 50.00%\n",
      "Epoch: 92, Accuracy: 69.46%\n",
      "Epoch: 93, Accuracy: 50.00%\n",
      "Epoch: 94, Accuracy: 50.00%\n",
      "Epoch: 95, Accuracy: 73.83%\n",
      "Epoch: 96, Accuracy: 27.35%\n",
      "Epoch: 97, Accuracy: 50.00%\n",
      "Epoch: 98, Accuracy: 50.00%\n",
      "Epoch: 99, Accuracy: 50.00%\n",
      "Epoch: 100, Accuracy: 30.70%\n",
      "Best Epoch: 87, Best Accuracy: 77.68%\n",
      "Optimal Epoch: 87, with Accuracy: 77.68%\n"
     ]
    }
   ],
   "source": [
    "import csv\n",
    "import random\n",
    "import math\n",
    "\n",
    "# 定义简单的前馈神经网络\n",
    "class SimpleNeuralNetwork:\n",
    "    def __init__(self, input_size, hidden_size, output_size):\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.output_size = output_size\n",
    "\n",
    "        # 初始化权重\n",
    "        self.weights_input_hidden = [[random.uniform(-0.5, 0.5) for _ in range(hidden_size)] for _ in range(input_size)]\n",
    "        self.weights_hidden_output = [[random.uniform(-0.5,0.5) for _ in range(output_size)] for _ in range(hidden_size)]\n",
    "\n",
    "        # 初始化偏置\n",
    "        self.bias_hidden = [random.uniform(-0.5,0.5) for _ in range(hidden_size)]\n",
    "        self.bias_output = [random.uniform(-0.5,0.5) for _ in range(output_size)]\n",
    "\n",
    "    def sigmoid(self, x):\n",
    "        return 1 / (1 + math.exp(-x))\n",
    "\n",
    "    def sigmoid_derivative(self, x):\n",
    "        return x * (1 - x)\n",
    "\n",
    "    def feedforward(self, inputs):\n",
    "        # 计算隐藏层输出\n",
    "        hidden_layer_input = [sum(i * w for i, w in zip(inputs, col))+b for col,b in zip(zip(*self.weights_input_hidden),self.bias_hidden)]\n",
    "        hidden_layer_output = [self.sigmoid(x) for x in hidden_layer_input]\n",
    "\n",
    "        # 计算输出层输出\n",
    "        output_layer_input = [sum(h * w for h, w in zip(hidden_layer_output, col))+b for col,b in zip(zip(*self.weights_hidden_output),self.bias_output)]\n",
    "        output_layer_output = [self.sigmoid(x) for x in output_layer_input]\n",
    "\n",
    "        return hidden_layer_output, output_layer_output\n",
    "\n",
    "    def train(self, training_data, labels, learning_rate, epochs):\n",
    "        for _ in range(epochs):\n",
    "            for inputs, label in zip(training_data, labels):\n",
    "                # 前向传播\n",
    "                hidden_output, predicted_output = self.feedforward(inputs)\n",
    "\n",
    "                # 计算输出层误差\n",
    "                output_errors = [label - output for output in predicted_output]\n",
    "                output_delta = [error * self.sigmoid_derivative(output) for error, output in zip(output_errors, predicted_output)]\n",
    "\n",
    "                # 计算隐藏层误差\n",
    "                hidden_errors = [sum(w * delta for w, delta in zip(col, output_delta)) for col in self.weights_hidden_output]\n",
    "                hidden_delta = [error * self.sigmoid_derivative(output) for error, output in zip(hidden_errors, hidden_output)]\n",
    "\n",
    "                # 更新隐藏层到输出层的权重和偏置\n",
    "                for i in range(self.hidden_size):\n",
    "                    for j in range(self.output_size):\n",
    "                        self.weights_hidden_output[i][j] += learning_rate * output_delta[j] * hidden_output[i]\n",
    "                for j in range(self.output_size):\n",
    "                    self.bias_output[j] += learning_rate * output_delta[j]\n",
    "\n",
    "                # 更新输入层到隐藏层的权重\n",
    "                for i in range(self.input_size):\n",
    "                    for j in range(self.hidden_size):\n",
    "                        self.weights_input_hidden[i][j] += learning_rate * hidden_delta[j] * inputs[i]\n",
    "                for j in range(self.output_size):\n",
    "                    self.bias_hidden[j] += learning_rate * hidden_delta[j]\n",
    "\n",
    "    def predict(self, inputs):\n",
    "        _, output = self.feedforward(inputs)\n",
    "        return output.index(max(output))\n",
    "\n",
    "\n",
    "\n",
    "# 自动调整epoch数寻找最优模型\n",
    "def find_best_epoch(data, labels, input_size, hidden_size, output_size, learning_rate, max_epochs):\n",
    "    best_accuracy = 0\n",
    "    best_epoch = 0\n",
    "    best_model = None\n",
    "\n",
    "    for epoch in range(1, max_epochs + 1):\n",
    "        nn = SimpleNeuralNetwork(input_size, hidden_size, output_size)\n",
    "        nn.train(data, labels, learning_rate, epoch)\n",
    "\n",
    "        correct = 0\n",
    "        for inputs, label in zip(data, labels):\n",
    "            prediction = nn.predict(inputs)\n",
    "            if prediction == label:\n",
    "                correct += 1\n",
    "\n",
    "        accuracy = correct / len(data)\n",
    "        print(f'Epoch: {epoch}, Accuracy: {accuracy * 100:.2f}%')\n",
    "\n",
    "        if accuracy > best_accuracy:\n",
    "            best_accuracy = accuracy\n",
    "            best_epoch = epoch\n",
    "            best_model = nn\n",
    "\n",
    "    print(f'Best Epoch: {best_epoch}, Best Accuracy: {best_accuracy * 100:.2f}%')\n",
    "    return best_model, best_epoch, best_accuracy\n",
    "\n",
    "# 数据集信息\n",
    "input_size = len(X_train[0])\n",
    "hidden_size = 5\n",
    "output_size = len(set(y_train))\n",
    "learning_rate = 0.01\n",
    "max_epochs = 100\n",
    "\n",
    "# 找到最佳的epoch数和模型\n",
    "best_model, best_epoch, best_accuracy = find_best_epoch(X_train, y_train, input_size, hidden_size, output_size, learning_rate, max_epochs)\n",
    "\n",
    "print(f'Optimal Epoch: {best_epoch}, with Accuracy: {best_accuracy * 100:.2f}%')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 71.39%\n",
      "混淆矩阵：\n",
      " [[181  97]\n",
      " [  4  71]]\n",
      "准确率： 0.7138810198300283\n"
     ]
    }
   ],
   "source": [
    "from sklearn import  metrics\n",
    "# 验证精度\n",
    "correct = 0\n",
    "y_test_pred=[]\n",
    "for inputs, label in zip(X_test, y_test):\n",
    "    prediction = best_model.predict(inputs)\n",
    "    y_test_pred.append(prediction)\n",
    "    if prediction == label:\n",
    "        correct += 1\n",
    "\n",
    "accuracy = correct / len(X_test)\n",
    "print(f'Accuracy: {accuracy * 100:.2f}%')\n",
    "confusion_matrix = metrics.confusion_matrix(y_test, y_test_pred)\n",
    "accuracy_rate=metrics.accuracy_score(y_test, y_test_pred)\n",
    "print(\"混淆矩阵：\\n\",confusion_matrix)\n",
    "print(\"准确率：\",accuracy_rate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调整类别权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1, Accuracy: 50.00%\n",
      "Epoch: 2, Accuracy: 49.68%\n",
      "Epoch: 3, Accuracy: 44.28%\n",
      "Epoch: 4, Accuracy: 50.00%\n",
      "Epoch: 5, Accuracy: 30.95%\n",
      "Epoch: 6, Accuracy: 58.24%\n",
      "Epoch: 7, Accuracy: 51.31%\n",
      "Epoch: 8, Accuracy: 63.78%\n",
      "Epoch: 9, Accuracy: 48.15%\n",
      "Epoch: 10, Accuracy: 50.00%\n",
      "Epoch: 11, Accuracy: 66.26%\n",
      "Epoch: 12, Accuracy: 65.63%\n",
      "Epoch: 13, Accuracy: 35.54%\n",
      "Epoch: 14, Accuracy: 50.00%\n",
      "Epoch: 15, Accuracy: 33.83%\n",
      "Epoch: 16, Accuracy: 68.02%\n",
      "Epoch: 17, Accuracy: 65.59%\n",
      "Epoch: 18, Accuracy: 32.61%\n",
      "Epoch: 19, Accuracy: 50.00%\n",
      "Epoch: 20, Accuracy: 53.78%\n",
      "Epoch: 21, Accuracy: 35.18%\n",
      "Epoch: 22, Accuracy: 77.12%\n",
      "Epoch: 23, Accuracy: 50.00%\n",
      "Epoch: 24, Accuracy: 41.67%\n",
      "Epoch: 25, Accuracy: 66.62%\n",
      "Epoch: 26, Accuracy: 56.67%\n",
      "Epoch: 27, Accuracy: 67.16%\n",
      "Epoch: 28, Accuracy: 33.20%\n",
      "Epoch: 29, Accuracy: 46.17%\n",
      "Epoch: 30, Accuracy: 30.27%\n",
      "Epoch: 31, Accuracy: 34.41%\n",
      "Epoch: 32, Accuracy: 50.00%\n",
      "Epoch: 33, Accuracy: 66.17%\n",
      "Epoch: 34, Accuracy: 65.77%\n",
      "Epoch: 35, Accuracy: 65.63%\n",
      "Epoch: 36, Accuracy: 32.61%\n",
      "Epoch: 37, Accuracy: 54.68%\n",
      "Epoch: 38, Accuracy: 36.67%\n",
      "Epoch: 39, Accuracy: 65.77%\n",
      "Epoch: 40, Accuracy: 35.36%\n",
      "Epoch: 41, Accuracy: 68.96%\n",
      "Epoch: 42, Accuracy: 65.45%\n",
      "Epoch: 43, Accuracy: 50.00%\n",
      "Epoch: 44, Accuracy: 49.91%\n",
      "Epoch: 45, Accuracy: 42.43%\n",
      "Epoch: 46, Accuracy: 33.20%\n",
      "Epoch: 47, Accuracy: 33.38%\n",
      "Epoch: 48, Accuracy: 65.86%\n",
      "Epoch: 49, Accuracy: 65.72%\n",
      "Epoch: 50, Accuracy: 31.89%\n",
      "Epoch: 51, Accuracy: 64.91%\n",
      "Epoch: 52, Accuracy: 73.56%\n",
      "Epoch: 53, Accuracy: 56.94%\n",
      "Epoch: 54, Accuracy: 63.02%\n",
      "Epoch: 55, Accuracy: 59.41%\n",
      "Epoch: 56, Accuracy: 50.00%\n",
      "Epoch: 57, Accuracy: 65.23%\n",
      "Epoch: 58, Accuracy: 50.00%\n",
      "Epoch: 59, Accuracy: 50.00%\n",
      "Epoch: 60, Accuracy: 32.66%\n",
      "Epoch: 61, Accuracy: 50.00%\n",
      "Epoch: 62, Accuracy: 64.95%\n",
      "Epoch: 63, Accuracy: 33.29%\n",
      "Epoch: 64, Accuracy: 67.12%\n",
      "Epoch: 65, Accuracy: 33.47%\n",
      "Epoch: 66, Accuracy: 65.05%\n",
      "Epoch: 67, Accuracy: 50.00%\n",
      "Epoch: 68, Accuracy: 50.00%\n",
      "Epoch: 69, Accuracy: 34.95%\n",
      "Epoch: 70, Accuracy: 65.68%\n",
      "Epoch: 71, Accuracy: 66.26%\n",
      "Epoch: 72, Accuracy: 33.38%\n",
      "Epoch: 73, Accuracy: 32.88%\n",
      "Epoch: 74, Accuracy: 35.63%\n",
      "Epoch: 75, Accuracy: 50.00%\n",
      "Epoch: 76, Accuracy: 63.51%\n",
      "Epoch: 77, Accuracy: 50.00%\n",
      "Epoch: 78, Accuracy: 64.64%\n",
      "Epoch: 79, Accuracy: 40.23%\n",
      "Epoch: 80, Accuracy: 65.36%\n",
      "Epoch: 81, Accuracy: 71.22%\n",
      "Epoch: 82, Accuracy: 32.70%\n",
      "Epoch: 83, Accuracy: 50.00%\n",
      "Epoch: 84, Accuracy: 65.23%\n",
      "Epoch: 85, Accuracy: 65.68%\n",
      "Epoch: 86, Accuracy: 38.11%\n",
      "Epoch: 87, Accuracy: 63.69%\n",
      "Epoch: 88, Accuracy: 50.00%\n",
      "Epoch: 89, Accuracy: 32.61%\n",
      "Epoch: 90, Accuracy: 50.00%\n",
      "Epoch: 91, Accuracy: 65.36%\n",
      "Epoch: 92, Accuracy: 36.98%\n",
      "Epoch: 93, Accuracy: 34.32%\n",
      "Epoch: 94, Accuracy: 50.99%\n",
      "Epoch: 95, Accuracy: 50.00%\n",
      "Epoch: 96, Accuracy: 48.60%\n",
      "Epoch: 97, Accuracy: 67.34%\n",
      "Epoch: 98, Accuracy: 34.95%\n",
      "Epoch: 99, Accuracy: 31.89%\n",
      "Epoch: 100, Accuracy: 34.95%\n",
      "Best Epoch: 22, Best Accuracy: 77.12%\n"
     ]
    }
   ],
   "source": [
    "class SimpleNeuralNetwork:\n",
    "    def __init__(self, input_size, hidden_size, output_size):\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.output_size = output_size\n",
    "\n",
    "        self.weights_input_hidden = [[random.random() for _ in range(hidden_size)] for _ in range(input_size)]\n",
    "        self.weights_hidden_output = [[random.random() for _ in range(output_size)] for _ in range(hidden_size)]\n",
    "\n",
    "    def sigmoid(self, x):\n",
    "        return 1 / (1 + math.exp(-x))\n",
    "\n",
    "    def sigmoid_derivative(self, x):\n",
    "        return x * (1 - x)\n",
    "\n",
    "    def feedforward(self, inputs):\n",
    "        hidden_layer_input = [sum(i * w for i, w in zip(inputs, col)) for col in zip(*self.weights_input_hidden)]\n",
    "        hidden_layer_output = [self.sigmoid(x) for x in hidden_layer_input]\n",
    "\n",
    "        output_layer_input = [sum(h * w for h, w in zip(hidden_layer_output, col)) for col in zip(*self.weights_hidden_output)]\n",
    "        output_layer_output = [self.sigmoid(x) for x in output_layer_input]\n",
    "\n",
    "        return hidden_layer_output, output_layer_output\n",
    "\n",
    "    def train(self, training_data, labels, learning_rate, epochs, class_weights):\n",
    "        for _ in range(epochs):\n",
    "            for inputs, label in zip(training_data, labels):\n",
    "                hidden_output, predicted_output = self.feedforward(inputs)\n",
    "                \n",
    "                output_errors = [label - output for output in predicted_output]\n",
    "                output_delta = [error * self.sigmoid_derivative(output) for error, output in zip(output_errors, predicted_output)]\n",
    "                \n",
    "                weight = class_weights[label]\n",
    "                \n",
    "                hidden_errors = [sum(w * delta for w, delta in zip(col, output_delta)) for col in self.weights_hidden_output]\n",
    "                hidden_delta = [error * self.sigmoid_derivative(output) * weight for error, output in zip(hidden_errors, hidden_output)]\n",
    "                \n",
    "                for i in range(self.hidden_size):\n",
    "                    for j in range(self.output_size):\n",
    "                        self.weights_hidden_output[i][j] += learning_rate * output_delta[j] * hidden_output[i]\n",
    "\n",
    "                for i in range(self.input_size):\n",
    "                    for j in range(self.hidden_size):\n",
    "                        self.weights_input_hidden[i][j] += learning_rate * hidden_delta[j] * inputs[i]\n",
    "\n",
    "    def predict(self, inputs):\n",
    "        _, output = self.feedforward(inputs)\n",
    "        return output.index(max(output))\n",
    "\n",
    "# 计算类权重\n",
    "# class_counts = {0: y_train.count(0), 1: y_train.count(1)}\n",
    "total_samples = len(y_train)\n",
    "class_weights = {label: total_samples / count for label, count in Counter(y_train).items()}\n",
    "\n",
    "# 自动调整epoch数寻找最优模型\n",
    "def find_best_epoch(data, labels, input_size, hidden_size, output_size, learning_rate, max_epochs, class_weights):\n",
    "    best_accuracy = 0\n",
    "    best_epoch = 0\n",
    "    best_model = None\n",
    "\n",
    "    for epoch in range(1, max_epochs + 1):\n",
    "        nn = SimpleNeuralNetwork(input_size, hidden_size, output_size)\n",
    "        nn.train(data, labels, learning_rate, epoch, class_weights)\n",
    "\n",
    "        correct = 0\n",
    "        for inputs, label in zip(data, labels):\n",
    "            prediction = nn.predict(inputs)\n",
    "            if prediction == label:\n",
    "                correct += 1\n",
    "\n",
    "        accuracy = correct / len(data)\n",
    "        print(f'Epoch: {epoch}, Accuracy: {accuracy * 100:.2f}%')\n",
    "\n",
    "        if accuracy > best_accuracy:\n",
    "            best_accuracy = accuracy\n",
    "            best_epoch = epoch\n",
    "            best_model = nn\n",
    "\n",
    "    print(f'Best Epoch: {best_epoch}, Best Accuracy: {best_accuracy * 100:.2f}%')\n",
    "    return best_model, best_epoch, best_accuracy\n",
    "\n",
    "input_size = len(X_train[0])\n",
    "hidden_size = 5\n",
    "output_size = len(set(y_train))\n",
    "learning_rate = 0.1\n",
    "max_epochs = 100\n",
    "\n",
    "best_model, best_epoch, best_accuracy = find_best_epoch(X_train, y_train ,input_size, hidden_size, output_size, learning_rate, max_epochs, class_weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 输出（未进行过采样）：\n",
    "发现模型对第二类分类能力很差，有一半错分，考虑使用过采样平衡两类样本数    \n",
    "Accuracy: 51.56%     \n",
    "Epoch: 1, Accuracy: 29.62%\n",
    "Epoch: 2, Accuracy: 78.84%\n",
    "Epoch: 3, Accuracy: 21.16%\n",
    "Epoch: 4, Accuracy: 78.84%\n",
    "Epoch: 5, Accuracy: 72.23%\n",
    "Epoch: 6, Accuracy: 21.16%\n",
    "Epoch: 7, Accuracy: 29.05%\n",
    "Epoch: 8, Accuracy: 78.84%\n",
    "Epoch: 9, Accuracy: 21.16%\n",
    "Epoch: 10, Accuracy: 21.16%\n",
    "Epoch: 11, Accuracy: 21.16%\n",
    "Epoch: 12, Accuracy: 78.84%\n",
    "Epoch: 13, Accuracy: 21.16%\n",
    "Epoch: 14, Accuracy: 21.16%\n",
    "Epoch: 15, Accuracy: 21.16%\n",
    "Epoch: 16, Accuracy: 21.16%\n",
    "Epoch: 17, Accuracy: 78.84%\n",
    "Epoch: 18, Accuracy: 55.40%\n",
    "Epoch: 19, Accuracy: 21.16%\n",
    "Epoch: 20, Accuracy: 78.84%\n",
    "Epoch: 21, Accuracy: 21.16%\n",
    "Epoch: 22, Accuracy: 78.84%\n",
    "Epoch: 23, Accuracy: 21.16%\n",
    "Epoch: 24, Accuracy: 21.16%\n",
    "Epoch: 25, Accuracy: 62.64%\n",
    "Epoch: 26, Accuracy: 78.84%\n",
    "Epoch: 27, Accuracy: 78.84%\n",
    "Epoch: 28, Accuracy: 21.16%\n",
    "Epoch: 29, Accuracy: 56.39%\n",
    "Epoch: 30, Accuracy: 78.84%\n",
    "Epoch: 31, Accuracy: 84.66%\n",
    "Epoch: 32, Accuracy: 21.16%\n",
    "Epoch: 33, Accuracy: 78.84%\n",
    "Epoch: 34, Accuracy: 37.78%\n",
    "Epoch: 35, Accuracy: 21.16%\n",
    "Epoch: 36, Accuracy: 41.26%\n",
    "Epoch: 37, Accuracy: 50.85%\n",
    "Epoch: 38, Accuracy: 24.43%\n",
    "Epoch: 39, Accuracy: 78.84%\n",
    "Epoch: 40, Accuracy: 78.84%\n",
    "Epoch: 41, Accuracy: 56.46%\n",
    "Epoch: 42, Accuracy: 28.76%\n",
    "Epoch: 43, Accuracy: 54.26%\n",
    "Epoch: 44, Accuracy: 23.44%\n",
    "Epoch: 45, Accuracy: 72.02%\n",
    "Epoch: 46, Accuracy: 27.20%\n",
    "Epoch: 47, Accuracy: 78.84%\n",
    "Epoch: 48, Accuracy: 63.78%\n",
    "Epoch: 49, Accuracy: 21.16%\n",
    "Epoch: 50, Accuracy: 21.16%\n",
    "Epoch: 51, Accuracy: 78.84%\n",
    "Epoch: 52, Accuracy: 38.21%\n",
    "Epoch: 53, Accuracy: 21.16%\n",
    "Epoch: 54, Accuracy: 78.84%\n",
    "Epoch: 55, Accuracy: 52.06%\n",
    "Epoch: 56, Accuracy: 40.27%\n",
    "Epoch: 57, Accuracy: 78.27%\n",
    "Epoch: 58, Accuracy: 40.91%\n",
    "Epoch: 59, Accuracy: 63.92%\n",
    "Epoch: 60, Accuracy: 21.16%\n",
    "Epoch: 61, Accuracy: 21.16%\n",
    "Epoch: 62, Accuracy: 21.16%\n",
    "Epoch: 63, Accuracy: 21.16%\n",
    "Epoch: 64, Accuracy: 64.20%\n",
    "Epoch: 65, Accuracy: 70.03%\n",
    "Epoch: 66, Accuracy: 21.16%\n",
    "Epoch: 67, Accuracy: 21.16%\n",
    "Epoch: 68, Accuracy: 21.16%\n",
    "Epoch: 69, Accuracy: 78.41%\n",
    "Epoch: 70, Accuracy: 21.16%\n",
    "Epoch: 71, Accuracy: 70.88%\n",
    "Epoch: 72, Accuracy: 78.84%\n",
    "Epoch: 73, Accuracy: 22.16%\n",
    "Epoch: 74, Accuracy: 77.70%\n",
    "Epoch: 75, Accuracy: 24.64%\n",
    "Epoch: 76, Accuracy: 39.42%\n",
    "Epoch: 77, Accuracy: 78.84%\n",
    "Epoch: 78, Accuracy: 21.16%\n",
    "Epoch: 79, Accuracy: 33.74%\n",
    "Epoch: 80, Accuracy: 78.84%\n",
    "Epoch: 81, Accuracy: 78.84%\n",
    "Epoch: 82, Accuracy: 53.27%\n",
    "Epoch: 83, Accuracy: 78.84%\n",
    "Epoch: 84, Accuracy: 21.16%\n",
    "Epoch: 85, Accuracy: 78.84%\n",
    "Epoch: 86, Accuracy: 47.16%\n",
    "Epoch: 87, Accuracy: 78.84%\n",
    "Epoch: 88, Accuracy: 43.11%\n",
    "Epoch: 89, Accuracy: 78.76%\n",
    "Epoch: 90, Accuracy: 23.08%\n",
    "Epoch: 91, Accuracy: 78.84%\n",
    "Epoch: 92, Accuracy: 29.33%\n",
    "Epoch: 93, Accuracy: 31.68%\n",
    "Epoch: 94, Accuracy: 38.85%\n",
    "Epoch: 95, Accuracy: 52.77%\n",
    "Epoch: 96, Accuracy: 62.07%\n",
    "Epoch: 97, Accuracy: 36.86%\n",
    "Epoch: 98, Accuracy: 55.68%\n",
    "Epoch: 99, Accuracy: 48.58%\n",
    "Epoch: 100, Accuracy: 75.07%\n",
    "Best Epoch: 31, Best Accuracy: 84.66%\n",
    "Optimal Epoch: 31, with Accuracy: 84.66%     \n",
    "Accuracy: 86.12%\n",
    "混淆矩阵：\n",
    " [[266  12]\n",
    " [ 37  38]]\n",
    "准确率： 0.8611898016997167\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "myenv2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
